Skip to content

Commit 29ac061

Browse files
PRC-500: Reconciliation endpoint for sync checks
1 parent e9889bb commit 29ac061

File tree

8 files changed

+107
-1
lines changed

8 files changed

+107
-1
lines changed

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

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

3+
import org.springframework.data.domain.Pageable
34
import org.springframework.stereotype.Service
45
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateAddressPhoneRequest
56
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateAddressRequest
@@ -90,6 +91,8 @@ class SyncFacade(
9091
)
9192
}
9293

94+
fun getIds(pageable: Pageable) = syncOrganisationService.getOrganisationIds(pageable)
95+
9396
// ================================================================
9497
// Organisation phone numbers
9598
// ================================================================

src/main/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/mapping/sync/SyncOrganisationMappers.kt

+6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package uk.gov.justice.digital.hmpps.organisationsapi.mapping.sync
22

3+
import org.springframework.data.domain.Page
34
import uk.gov.justice.digital.hmpps.organisationsapi.entity.OrganisationWithFixedIdEntity
45
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateOrganisationRequest
6+
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationId
57
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationResponse
68

79
fun OrganisationWithFixedIdEntity.toModel(): SyncOrganisationResponse = SyncOrganisationResponse(
@@ -35,3 +37,7 @@ fun SyncCreateOrganisationRequest.toEntity() = OrganisationWithFixedIdEntity(
3537
updatedBy = this.updatedBy,
3638
updatedTime = this.updatedTime,
3739
)
40+
41+
fun OrganisationWithFixedIdEntity.toModelIds(): SyncOrganisationId = SyncOrganisationId(organisationId = this.organisationId)
42+
43+
fun Page<OrganisationWithFixedIdEntity>.toModelIds(): Page<SyncOrganisationId> = map { it.toModelIds() }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
5+
@Schema(description = "Response object for email address changes via sync")
6+
data class SyncOrganisationId(
7+
@Schema(description = "The ID for an organisation", example = "111111")
8+
val organisationId: Long,
9+
)

src/main/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/resource/sync/SyncOrganisationController.kt

+27
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses
99
import io.swagger.v3.oas.annotations.security.SecurityRequirement
1010
import io.swagger.v3.oas.annotations.tags.Tag
1111
import jakarta.validation.Valid
12+
import org.springdoc.core.annotations.ParameterObject
13+
import org.springframework.data.domain.Page
14+
import org.springframework.data.domain.Pageable
15+
import org.springframework.data.domain.Sort.Direction
16+
import org.springframework.data.web.PageableDefault
1217
import org.springframework.http.MediaType
1318
import org.springframework.security.access.prepost.PreAuthorize
1419
import org.springframework.web.bind.annotation.DeleteMapping
@@ -23,6 +28,7 @@ import org.springframework.web.bind.annotation.RestController
2328
import uk.gov.justice.digital.hmpps.organisationsapi.facade.SyncFacade
2429
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateOrganisationRequest
2530
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateOrganisationRequest
31+
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationId
2632
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationResponse
2733
import uk.gov.justice.digital.hmpps.organisationsapi.swagger.AuthApiResponses
2834
import uk.gov.justice.hmpps.kotlin.common.ErrorResponse
@@ -174,4 +180,25 @@ class SyncOrganisationController(val syncFacade: SyncFacade) {
174180
@PathVariable organisationId: Long,
175181
@Valid @RequestBody updateOrganisationRequest: SyncUpdateOrganisationRequest,
176182
) = syncFacade.updateOrganisation(organisationId, updateOrganisationRequest)
183+
184+
@GetMapping("/organisations/reconcile")
185+
@Operation(
186+
summary = "Reconciliation endpoint",
187+
description = "Get a paged list of existing organisation IDs to reconcile against",
188+
security = [SecurityRequirement(name = "bearer")],
189+
)
190+
@ApiResponses(
191+
value = [
192+
ApiResponse(
193+
responseCode = "200",
194+
description = "Pageable organisation IDs returned",
195+
),
196+
],
197+
)
198+
@PreAuthorize("hasAnyRole('ROLE_ORGANISATIONS_MIGRATION')")
199+
fun reconcileOrganisations(
200+
@ParameterObject
201+
@PageableDefault(sort = ["organisationId"], size = 100, direction = Direction.ASC)
202+
pageable: Pageable,
203+
): Page<SyncOrganisationId> = syncFacade.getIds(pageable)
177204
}

src/main/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/service/sync/SyncOrganisationService.kt

+7
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package uk.gov.justice.digital.hmpps.organisationsapi.service.sync
22

33
import jakarta.persistence.EntityNotFoundException
44
import org.slf4j.LoggerFactory
5+
import org.springframework.data.domain.Page
6+
import org.springframework.data.domain.Pageable
57
import org.springframework.stereotype.Service
68
import org.springframework.transaction.annotation.Transactional
79
import uk.gov.justice.digital.hmpps.organisationsapi.mapping.sync.toEntity
810
import uk.gov.justice.digital.hmpps.organisationsapi.mapping.sync.toModel
11+
import uk.gov.justice.digital.hmpps.organisationsapi.mapping.sync.toModelIds
912
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateOrganisationRequest
1013
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateOrganisationRequest
14+
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationId
1115
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationResponse
1216
import uk.gov.justice.digital.hmpps.organisationsapi.repository.OrganisationWithFixedIdRepository
1317

@@ -78,4 +82,7 @@ class SyncOrganisationService(
7882

7983
return organisationRepository.saveAndFlush(changedOrganisation).toModel()
8084
}
85+
86+
fun getOrganisationIds(pageable: Pageable): Page<SyncOrganisationId> =
87+
organisationRepository.findAll(pageable).toModelIds()
8188
}

src/test/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/integration/helper/TestAPIClient.kt

+26
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import uk.gov.justice.digital.hmpps.organisationsapi.model.response.migrate.Migr
1919
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncAddressPhoneResponse
2020
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncAddressResponse
2121
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncEmailResponse
22+
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationId
2223
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationResponse
2324
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncPhoneResponse
2425
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncWebResponse
@@ -162,6 +163,17 @@ class TestAPIClient(private val webTestClient: WebTestClient, private val jwtAut
162163
.expectBody(SyncWebResponse::class.java)
163164
.returnResult().responseBody!!
164165

166+
fun syncReconcileOrganisations(page: Long = 0, size: Long = 10) = webTestClient.get()
167+
.uri("/sync/organisations/reconcile?page=$page&size=$size")
168+
.accept(MediaType.APPLICATION_JSON)
169+
.headers(setAuthorisation(roles = listOf("ROLE_ORGANISATIONS_MIGRATION")))
170+
.exchange()
171+
.expectStatus()
172+
.isOk
173+
.expectHeader().contentType(MediaType.APPLICATION_JSON)
174+
.expectBody(OrganisationIdsResponse::class.java)
175+
.returnResult().responseBody!!
176+
165177
fun getBadResponseErrors(uri: URI) = webTestClient.get()
166178
.uri(uri.toString())
167179
.accept(MediaType.APPLICATION_JSON)
@@ -225,4 +237,18 @@ class TestAPIClient(private val webTestClient: WebTestClient, private val jwtAut
225237
val unsorted: Boolean,
226238
val sorted: Boolean,
227239
)
240+
241+
data class OrganisationIdsResponse(
242+
val content: List<SyncOrganisationId>,
243+
val pageable: ReturnedPageable,
244+
val last: Boolean,
245+
val totalPages: Int,
246+
val totalElements: Int,
247+
val first: Boolean,
248+
val size: Int,
249+
val number: Int,
250+
val sort: ReturnedSort,
251+
val numberOfElements: Int,
252+
val empty: Boolean,
253+
)
228254
}

src/test/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/integration/resource/OrganisationSearchIntegrationTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class OrganisationSearchIntegrationTest : SecureApiIntegrationTestBase() {
4141
}
4242

4343
@ParameterizedTest
44-
@ValueSource(strings = ["ROLE_ORGANISATIONS__R", "ROLE_ORGANISATONS__RW"])
44+
@ValueSource(strings = ["ROLE_ORGANISATIONS__R", "ROLE_ORGANISATIONS__RW"])
4545
fun `should return empty list if no organisation found and work with all roles`(role: String) {
4646
val response = testAPIClient.searchOrganisations(OrganisationSearchRequest("ABC"))
4747
assertThat(response.empty).isTrue()

src/test/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/integration/resource/sync/SyncOrganisationsIntegrationTest.kt

+28
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.springframework.http.HttpStatus
88
import org.springframework.http.MediaType
99
import org.springframework.test.context.TestPropertySource
1010
import uk.gov.justice.digital.hmpps.organisationsapi.integration.PostgresIntegrationTestBase
11+
import uk.gov.justice.digital.hmpps.organisationsapi.integration.helper.hasSize
1112
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateOrganisationRequest
1213
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateOrganisationRequest
1314
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncOrganisationResponse
@@ -232,6 +233,33 @@ class SyncOrganisationsIntegrationTest : PostgresIntegrationTestBase() {
232233
stubEvents.assertHasNoEvents(OutboundEvent.ORGANISATION_CREATED)
233234
}
234235

236+
@Test
237+
fun `should support pageable organisation IDs for reconciliation`() {
238+
testAPIClient.syncCreateAnOrganisation(syncCreateOrganisationRequest(5005L))
239+
testAPIClient.syncCreateAnOrganisation(syncCreateOrganisationRequest(5006L))
240+
testAPIClient.syncCreateAnOrganisation(syncCreateOrganisationRequest(5007L))
241+
242+
val firstPage = testAPIClient.syncReconcileOrganisations(0, 2)
243+
with(firstPage) {
244+
assertThat(totalElements).isGreaterThanOrEqualTo(3)
245+
assertThat(content.hasSize(2))
246+
assertThat(content).extracting("organisationId").hasSize(2)
247+
}
248+
249+
val secondPage = testAPIClient.syncReconcileOrganisations(1, 2)
250+
with(secondPage) {
251+
assertThat(totalElements).isGreaterThanOrEqualTo(3)
252+
assertThat(content.size).isGreaterThanOrEqualTo(1)
253+
}
254+
255+
val bigPage = testAPIClient.syncReconcileOrganisations(0, 100)
256+
with(bigPage) {
257+
assertThat(totalElements).isGreaterThanOrEqualTo(3)
258+
assertThat(content.size).isGreaterThanOrEqualTo(3)
259+
assertThat(content).extracting("organisationId").containsAll(listOf(5005L, 5006L, 5007L))
260+
}
261+
}
262+
235263
private fun syncUpdateOrganisationRequest(organisationId: Long) = SyncUpdateOrganisationRequest(
236264
organisationId = organisationId,
237265
organisationName = "Organisation321",

0 commit comments

Comments
 (0)