From 1adbd5379b8253d39cb193d368eb0ac3e8f0d102 Mon Sep 17 00:00:00 2001 From: davidatkinsuk Date: Mon, 6 Jan 2025 12:15:03 +0000 Subject: [PATCH] Seed job to backfill space bookings from delius MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a seed job to backfill `SpaceBookings` for bookings that were created directly in delius It will create an offline application for every required booking, emulating the now removed ‘manual booking’ functionality --- .../jpa/entity/Cas1SpaceBookingEntity.kt | 2 +- .../jpa/entity/OfflineApplicationEntity.kt | 1 + .../cas1/Cas1DeliusBookingImportEntity.kt | 1 + .../approvedpremisesapi/seed/SeedService.kt | 2 + ...as1BackfillSpaceBookingsCreatedInDelius.kt | 177 +++++++++++++++ src/main/resources/static/_shared.yml | 1 + .../static/codegen/built-api-spec.yml | 1 + .../static/codegen/built-cas1-api-spec.yml | 1 + .../static/codegen/built-cas2-api-spec.yml | 1 + .../static/codegen/built-cas3-api-spec.yml | 1 + ...ackfillSpaceBookingsCreatedInDeliusTest.kt | 206 ++++++++++++++++++ .../SeedCas1BookingToSpaceBookingTest.kt | 2 +- ...ackfillSpaceBookingsCreatedInDeliusTest.kt | 46 ++++ 13 files changed, 440 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDelius.kt create mode 100644 src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BackfillSpaceBookingsCreatedInDeliusTest.kt rename src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/{seed/cas1 => cas1/seed}/SeedCas1BookingToSpaceBookingTest.kt (99%) create mode 100644 src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/unit/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDeliusTest.kt diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/Cas1SpaceBookingEntity.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/Cas1SpaceBookingEntity.kt index 30a6e5672d..9045c41288 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/Cas1SpaceBookingEntity.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/Cas1SpaceBookingEntity.kt @@ -286,7 +286,7 @@ data class Cas1SpaceBookingEntity( @JoinColumn(name = "placement_request_id") val placementRequest: PlacementRequestEntity?, /** - * createdAt will only be null for migrated [BookingEntity]s where no 'Booking Made' domain event + * createdBy will only be null for migrated [BookingEntity]s where no 'Booking Made' domain event * existed for the booking (i.e. those migrated into the system when it went live) */ @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/OfflineApplicationEntity.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/OfflineApplicationEntity.kt index bfb773e2ea..eee2ec726c 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/OfflineApplicationEntity.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/OfflineApplicationEntity.kt @@ -5,6 +5,7 @@ import jakarta.persistence.Id import jakarta.persistence.Table import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.OffenderService import java.time.OffsetDateTime import java.util.UUID diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1DeliusBookingImportEntity.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1DeliusBookingImportEntity.kt index 6035fb3d19..c26540ead0 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1DeliusBookingImportEntity.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1DeliusBookingImportEntity.kt @@ -12,6 +12,7 @@ import java.util.UUID @Repository interface Cas1DeliusBookingImportRepository : JpaRepository { fun findByBookingId(id: UUID): Cas1DeliusBookingImportEntity? + fun findByBookingIdIsNullAndPremisesQcode(qCode: String): List } @Entity diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/SeedService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/SeedService.kt index 053dc59208..1ce2470d85 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/SeedService.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/SeedService.kt @@ -10,6 +10,7 @@ import uk.gov.justice.digital.hmpps.approvedpremisesapi.config.SeedConfig import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.ApStaffUsersSeedJob import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.ApprovedPremisesBookingCancelSeedJob import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.ApprovedPremisesRoomsSeedJob +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1BackfillSpaceBookingsCreatedInDelius import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1BookingToSpaceBookingSeedJob import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1CruManagementAreaSeedJob import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1DomainEventReplaySeedJob @@ -90,6 +91,7 @@ class SeedService( SeedFileType.approvedPremisesImportDeliusReferrals -> getBean(Cas1ImportDeliusReferralsSeedJob::class) SeedFileType.approvedPremisesUpdateSpaceBooking -> getBean(Cas1UpdateSpaceBookingSeedJob::class) SeedFileType.temporaryAccommodationReferralRejection -> getBean(Cas3ReferralRejectionSeedJob::class) + SeedFileType.approvedPremisesBackfillSpaceBookingsCreatedInDelius -> getBean(Cas1BackfillSpaceBookingsCreatedInDelius::class) } val seedStarted = LocalDateTime.now() diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDelius.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDelius.kt new file mode 100644 index 0000000000..437c5c298b --- /dev/null +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDelius.kt @@ -0,0 +1,177 @@ +package uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1 + +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service +import org.springframework.transaction.support.TransactionTemplate +import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ServiceName +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.ApprovedPremisesEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.ApprovedPremisesRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.Cas1SpaceBookingEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.Cas1SpaceBookingRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.CharacteristicEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.OfflineApplicationEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.OfflineApplicationRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.cas1.Cas1DeliusBookingImportEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.cas1.Cas1DeliusBookingImportRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.model.PersonSummaryInfoResult +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.SeedJob +import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.EnvironmentService +import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.OffenderService +import java.time.OffsetDateTime +import java.util.UUID + +/** + * Before this job is ran, corresponding referrals must be imported from delius into the + * 'cas1_delius_booking_import' table using the [Cas1ImportDeliusReferralsSeedJob] job + */ +@Service +class Cas1BackfillSpaceBookingsCreatedInDelius( + private val approvedPremisesRepository: ApprovedPremisesRepository, + private val cas1DeliusBookingImportRepository: Cas1DeliusBookingImportRepository, + private val cas1BookingManagementInfoService: Cas1BookingManagementInfoService, + private val environmentService: EnvironmentService, + private val offenderService: OffenderService, + private val offlineApplicationRepository: OfflineApplicationRepository, + private val spaceBookingRepository: Cas1SpaceBookingRepository, + private val transactionTemplate: TransactionTemplate, +) : SeedJob( + requiredHeaders = setOf( + "q_code", + ), + runInTransaction = false, +) { + private val log = LoggerFactory.getLogger(this::class.java) + + override fun deserializeRow(columns: Map) = Cas1CreateMissingReferralsSeedCsvRow( + qCode = columns["q_code"]!!.trim(), + ) + + override fun preSeed() { + if (environmentService.isProd()) { + error("Cannot run seed job in prod") + } + } + + override fun processRow(row: Cas1CreateMissingReferralsSeedCsvRow) { + transactionTemplate.executeWithoutResult { + migratePremise(row.qCode) + } + } + + @SuppressWarnings("TooGenericExceptionCaught") + private fun migratePremise(qCode: String) { + val premises = approvedPremisesRepository.findByQCode(qCode) ?: error("Premises with qcode $qCode not found") + + if (!premises.supportsSpaceBookings) { + error("premise ${premises.name} doesn't support space bookings, can't migrate bookings") + } + + val referrals = cas1DeliusBookingImportRepository.findByBookingIdIsNullAndPremisesQcode(qCode) + + log.info("Will create ${referrals.size} space bookings for premise ${premises.name} ($qCode)") + + if (referrals.isEmpty()) { + return + } + + // TODO: we need a version of this that will segment calls to the backend + // can use for CAS3 report that does that? + val crnToName = offenderService.getPersonSummaryInfoResults( + crns = referrals.map { it.crn }.toSet(), + limitedAccessStrategy = OffenderService.LimitedAccessStrategy.IgnoreLimitedAccess, + ).associate { personSummaryInfoResult -> + val crn = personSummaryInfoResult.crn + when (personSummaryInfoResult) { + is PersonSummaryInfoResult.Success.Full -> { + val name = personSummaryInfoResult.summary.name + crn to "${name.forename} ${name.surname}" + } + is PersonSummaryInfoResult.NotFound, + is PersonSummaryInfoResult.Success.Restricted, + is PersonSummaryInfoResult.Unknown, + -> { + log.warn( + "Could not find offender for CRN $crn, " + + "result was ${personSummaryInfoResult::class}. Will not populate name", + ) + crn to null + } + } + } + + referrals.forEach { + createSpaceBooking( + premises = premises, + deliusReferral = it, + crnToName = crnToName, + ) + } + } + + private fun createSpaceBooking( + premises: ApprovedPremisesEntity, + deliusReferral: Cas1DeliusBookingImportEntity, + crnToName: Map, + ) { + val crn = deliusReferral.crn + + if (deliusReferral.expectedDepartureDate == null) { + log.warn("No expected departure date defined for crn $crn with arrival ${deliusReferral.arrivalDate}") + return + } + + val offlineApplication = offlineApplicationRepository.save( + OfflineApplicationEntity( + id = UUID.randomUUID(), + crn = crn, + service = ServiceName.approvedPremises.value, + createdAt = OffsetDateTime.now(), + eventNumber = deliusReferral.eventNumber, + name = crnToName[crn], + ), + ) + + val managementInfo = cas1BookingManagementInfoService.fromDeliusBookingImport(deliusReferral) + + spaceBookingRepository.save( + Cas1SpaceBookingEntity( + id = UUID.randomUUID(), + premises = premises, + application = null, + offlineApplication = offlineApplication, + placementRequest = null, + createdBy = null, + createdAt = OffsetDateTime.now(), + expectedArrivalDate = deliusReferral.expectedArrivalDate, + expectedDepartureDate = deliusReferral.expectedDepartureDate!!, + actualArrivalDate = managementInfo.arrivedAtDate, + actualArrivalTime = managementInfo.arrivedAtTime, + actualDepartureDate = managementInfo.departedAtDate, + actualDepartureTime = managementInfo.departedAtTime, + canonicalArrivalDate = managementInfo.arrivedAtDate ?: deliusReferral.expectedArrivalDate, + canonicalDepartureDate = managementInfo.departedAtDate ?: deliusReferral.expectedDepartureDate!!, + crn = deliusReferral.crn, + keyWorkerStaffCode = managementInfo.keyWorkerStaffCode, + keyWorkerName = managementInfo.keyWorkerName, + keyWorkerAssignedAt = null, + cancellationOccurredAt = null, + cancellationRecordedAt = null, + cancellationReason = null, + cancellationReasonNotes = null, + departureMoveOnCategory = managementInfo.departureMoveOnCategory, + departureReason = managementInfo.departureReason, + departureNotes = managementInfo.departureNotes, + criteria = emptyList().toMutableList(), + nonArrivalReason = managementInfo.nonArrivalReason, + nonArrivalConfirmedAt = managementInfo.nonArrivalConfirmedAt?.toInstant(), + nonArrivalNotes = managementInfo.nonArrivalNotes, + deliusEventNumber = deliusReferral.eventNumber, + migratedManagementInfoFrom = managementInfo.source, + ), + ) + } +} + +data class Cas1CreateMissingReferralsSeedCsvRow( + val qCode: String, +) diff --git a/src/main/resources/static/_shared.yml b/src/main/resources/static/_shared.yml index 91440ae3ce..e760505463 100644 --- a/src/main/resources/static/_shared.yml +++ b/src/main/resources/static/_shared.yml @@ -3726,6 +3726,7 @@ components: - approved_premises_space_planning_dry_run - approved_premises_import_delius_referrals - approved_premises_update_space_booking + - approved_premises_backfill_space_bookings_created_in_delius - temporary_accommodation_referral_rejection SeedFromExcelFileType: type: string diff --git a/src/main/resources/static/codegen/built-api-spec.yml b/src/main/resources/static/codegen/built-api-spec.yml index 53e7f5286e..624da3d4b1 100644 --- a/src/main/resources/static/codegen/built-api-spec.yml +++ b/src/main/resources/static/codegen/built-api-spec.yml @@ -8027,6 +8027,7 @@ components: - approved_premises_space_planning_dry_run - approved_premises_import_delius_referrals - approved_premises_update_space_booking + - approved_premises_backfill_space_bookings_created_in_delius - temporary_accommodation_referral_rejection SeedFromExcelFileType: type: string diff --git a/src/main/resources/static/codegen/built-cas1-api-spec.yml b/src/main/resources/static/codegen/built-cas1-api-spec.yml index 5e48de7441..df8f6d3d45 100644 --- a/src/main/resources/static/codegen/built-cas1-api-spec.yml +++ b/src/main/resources/static/codegen/built-cas1-api-spec.yml @@ -4948,6 +4948,7 @@ components: - approved_premises_space_planning_dry_run - approved_premises_import_delius_referrals - approved_premises_update_space_booking + - approved_premises_backfill_space_bookings_created_in_delius - temporary_accommodation_referral_rejection SeedFromExcelFileType: type: string diff --git a/src/main/resources/static/codegen/built-cas2-api-spec.yml b/src/main/resources/static/codegen/built-cas2-api-spec.yml index 742385e739..14f3d31518 100644 --- a/src/main/resources/static/codegen/built-cas2-api-spec.yml +++ b/src/main/resources/static/codegen/built-cas2-api-spec.yml @@ -4317,6 +4317,7 @@ components: - approved_premises_space_planning_dry_run - approved_premises_import_delius_referrals - approved_premises_update_space_booking + - approved_premises_backfill_space_bookings_created_in_delius - temporary_accommodation_referral_rejection SeedFromExcelFileType: type: string diff --git a/src/main/resources/static/codegen/built-cas3-api-spec.yml b/src/main/resources/static/codegen/built-cas3-api-spec.yml index e25e4aaba1..f4b64d78b8 100644 --- a/src/main/resources/static/codegen/built-cas3-api-spec.yml +++ b/src/main/resources/static/codegen/built-cas3-api-spec.yml @@ -3825,6 +3825,7 @@ components: - approved_premises_space_planning_dry_run - approved_premises_import_delius_referrals - approved_premises_update_space_booking + - approved_premises_backfill_space_bookings_created_in_delius - temporary_accommodation_referral_rejection SeedFromExcelFileType: type: string diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BackfillSpaceBookingsCreatedInDeliusTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BackfillSpaceBookingsCreatedInDeliusTest.kt new file mode 100644 index 0000000000..003b17c788 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BackfillSpaceBookingsCreatedInDeliusTest.kt @@ -0,0 +1,206 @@ +package uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.cas1.seed + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.SeedFileType +import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ServiceName +import uk.gov.justice.digital.hmpps.approvedpremisesapi.factory.CaseSummaryFactory +import uk.gov.justice.digital.hmpps.approvedpremisesapi.factory.NameFactory +import uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.givens.givenAUser +import uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.givens.givenAnApprovedPremises +import uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.httpmocks.apDeliusContextAddListCaseSummaryToBulkResponse +import uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.seed.SeedTestBase +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.ApprovedPremisesEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.DepartureReasonEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.ManagementInfoSource +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.MoveOnCategoryEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.NonArrivalReasonEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.UserEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.cas1.Cas1DeliusBookingImportEntity +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.cas1.Cas1DeliusBookingImportRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.repository.Cas1SpaceBookingTestRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.CsvBuilder +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1CreateMissingReferralsSeedCsvRow +import uk.gov.justice.digital.hmpps.approvedpremisesapi.util.isWithinTheLastMinute +import java.time.Instant +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.util.UUID + +class SeedCas1BackfillSpaceBookingsCreatedInDeliusTest : SeedTestBase() { + + @Autowired + lateinit var cas1SpaceBookingTestRepository: Cas1SpaceBookingTestRepository + + @Autowired + lateinit var deliusBookingImportRepository: Cas1DeliusBookingImportRepository + + lateinit var premises: ApprovedPremisesEntity + lateinit var otherPremise: ApprovedPremisesEntity + lateinit var otherUser: UserEntity + + lateinit var departureReasonActive: DepartureReasonEntity + lateinit var moveOnCategory: MoveOnCategoryEntity + lateinit var nonArrivalReasonCode: NonArrivalReasonEntity + + @BeforeEach + fun setupReferenceData() { + premises = givenAnApprovedPremises( + name = "Premises 1", + supportsSpaceBookings = true, + ) + otherPremise = givenAnApprovedPremises( + name = "Premises 2", + supportsSpaceBookings = true, + ) + otherUser = givenAUser().first + + departureReasonEntityFactory.produceAndPersist { + withLegacyDeliusCategoryCode("dr1inactive") + withServiceScope(ServiceName.approvedPremises.value) + } + departureReasonActive = departureReasonEntityFactory.produceAndPersist { + withLegacyDeliusCategoryCode("dr1") + withServiceScope(ServiceName.approvedPremises.value) + } + moveOnCategory = moveOnCategoryEntityFactory.produceAndPersist { + withLegacyDeliusCategoryCode("moc1") + withServiceScope(ServiceName.approvedPremises.value) + } + nonArrivalReasonCode = nonArrivalReasonEntityFactory.produceAndPersist { + withLegacyDeliusReasonCode("narc1") + } + } + + @SuppressWarnings("LongMethod") + @Test + fun `Backfill Space Bookings from Delius Import`() { + apDeliusContextAddListCaseSummaryToBulkResponse( + listOf( + CaseSummaryFactory() + .withCrn("CRN1") + .withName( + NameFactory() + .withForename("Max") + .withSurname("Power") + .produce(), + ) + .produce(), + ), + ) + + val deliusBooking = Cas1DeliusBookingImportEntity( + id = UUID.randomUUID(), + bookingId = null, + crn = "CRN1", + eventNumber = "67", + keyWorkerStaffCode = "kw001", + keyWorkerForename = "kay", + keyWorkerMiddleName = "m", + keyWorkerSurname = "werker", + departureReasonCode = "dr1", + moveOnCategoryCode = "moc1", + moveOnCategoryDescription = null, + expectedArrivalDate = LocalDate.of(2024, 5, 9), + arrivalDate = LocalDate.of(2024, 5, 2), + expectedDepartureDate = LocalDate.of(2024, 6, 2), + departureDate = LocalDate.of(2024, 5, 4), + nonArrivalDate = LocalDate.of(3000, 1, 1), + nonArrivalContactDatetime = OffsetDateTime.of(LocalDateTime.of(2024, 2, 1, 9, 58, 23), ZoneOffset.UTC), + nonArrivalReasonCode = "narc1", + nonArrivalReasonDescription = null, + nonArrivalNotes = "the non arrival notes", + premisesQcode = premises.qCode, + ) + + deliusBookingImportRepository.save( + deliusBooking.copy( + id = UUID.randomUUID(), + ), + ) + + // booking with booking id (e.g. created in CAS1) is ignored + deliusBookingImportRepository.save( + deliusBooking.copy( + id = UUID.randomUUID(), + bookingId = UUID.randomUUID(), + ), + ) + + // booking for other premise is ignored + deliusBookingImportRepository.save( + deliusBooking.copy( + id = UUID.randomUUID(), + premisesQcode = otherPremise.qCode, + ), + ) + + withCsv( + "valid-csv", + rowsToCsv(listOf(Cas1CreateMissingReferralsSeedCsvRow(premises.qCode))), + ) + + seedService.seedData(SeedFileType.approvedPremisesBackfillSpaceBookingsCreatedInDelius, "valid-csv.csv") + + val premiseSpaceBookings = cas1SpaceBookingTestRepository.findByPremisesId(premises.id) + assertThat(premiseSpaceBookings).hasSize(1) + + val migratedBooking1 = premiseSpaceBookings[0] + + assertThat(migratedBooking1.crn).isEqualTo("CRN1") + assertThat(migratedBooking1.deliusEventNumber).isEqualTo("67") + assertThat(migratedBooking1.premises.id).isEqualTo(premises.id) + assertThat(migratedBooking1.placementRequest).isNull() + assertThat(migratedBooking1.createdBy).isNull() + assertThat(migratedBooking1.expectedArrivalDate).isEqualTo(LocalDate.of(2024, 5, 9)) + assertThat(migratedBooking1.expectedDepartureDate).isEqualTo(LocalDate.of(2024, 6, 2)) + assertThat(migratedBooking1.actualArrivalDate).isEqualTo(LocalDate.parse("2024-05-02")) + assertThat(migratedBooking1.actualArrivalTime).isNull() + assertThat(migratedBooking1.actualDepartureDate).isEqualTo(LocalDate.parse("2024-05-04")) + assertThat(migratedBooking1.actualDepartureTime).isNull() + assertThat(migratedBooking1.canonicalArrivalDate).isEqualTo(LocalDate.of(2024, 5, 2)) + assertThat(migratedBooking1.canonicalDepartureDate).isEqualTo(LocalDate.of(2024, 5, 4)) + assertThat(migratedBooking1.keyWorkerName).isEqualTo("kay werker") + assertThat(migratedBooking1.keyWorkerStaffCode).isEqualTo("kw001") + assertThat(migratedBooking1.keyWorkerAssignedAt).isNull() + assertThat(migratedBooking1.application).isNull() + assertThat(migratedBooking1.cancellationReason).isNull() + assertThat(migratedBooking1.cancellationOccurredAt).isNull() + assertThat(migratedBooking1.cancellationRecordedAt).isNull() + assertThat(migratedBooking1.cancellationReasonNotes).isNull() + assertThat(migratedBooking1.departureReason).isEqualTo(departureReasonActive) + assertThat(migratedBooking1.departureMoveOnCategory).isEqualTo(moveOnCategory) + assertThat(migratedBooking1.criteria).isEmpty() + assertThat(migratedBooking1.nonArrivalReason).isEqualTo(nonArrivalReasonCode) + assertThat(migratedBooking1.nonArrivalConfirmedAt).isEqualTo(Instant.parse("2024-02-01T09:58:23.00Z")) + assertThat(migratedBooking1.nonArrivalNotes).isEqualTo("the non arrival notes") + assertThat(migratedBooking1.migratedManagementInfoFrom).isEqualTo(ManagementInfoSource.DELIUS) + + val offlineApplication1 = migratedBooking1.offlineApplication!! + assertThat(offlineApplication1.crn).isEqualTo("CRN1") + assertThat(offlineApplication1.service).isEqualTo(ServiceName.approvedPremises.value) + assertThat(offlineApplication1.createdAt).isWithinTheLastMinute() + assertThat(offlineApplication1.eventNumber).isEqualTo("67") + assertThat(offlineApplication1.name).isEqualTo("Max Power") + } + + private fun rowsToCsv(rows: List): String { + val builder = CsvBuilder() + .withUnquotedFields( + "q_code", + ) + .newRow() + + rows.forEach { + builder + .withQuotedField(premises.qCode) + .newRow() + } + + return builder.build() + } +} diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/seed/cas1/SeedCas1BookingToSpaceBookingTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BookingToSpaceBookingTest.kt similarity index 99% rename from src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/seed/cas1/SeedCas1BookingToSpaceBookingTest.kt rename to src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BookingToSpaceBookingTest.kt index 1c3fdbb50f..c750c976f1 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/seed/cas1/SeedCas1BookingToSpaceBookingTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/seed/SeedCas1BookingToSpaceBookingTest.kt @@ -1,4 +1,4 @@ -package uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.seed.cas1 +package uk.gov.justice.digital.hmpps.approvedpremisesapi.integration.cas1.seed import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/unit/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDeliusTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/unit/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDeliusTest.kt new file mode 100644 index 0000000000..27e496d1d0 --- /dev/null +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/unit/seed/cas1/Cas1BackfillSpaceBookingsCreatedInDeliusTest.kt @@ -0,0 +1,46 @@ +package uk.gov.justice.digital.hmpps.approvedpremisesapi.unit.seed.cas1 + +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.springframework.transaction.support.TransactionTemplate +import uk.gov.justice.digital.hmpps.approvedpremisesapi.factory.ApprovedPremisesEntityFactory +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.ApprovedPremisesRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.Cas1SpaceBookingRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.OfflineApplicationRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.cas1.Cas1DeliusBookingImportRepository +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1BackfillSpaceBookingsCreatedInDelius +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1BookingManagementInfoService +import uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1.Cas1CreateMissingReferralsSeedCsvRow +import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.EnvironmentService +import uk.gov.justice.digital.hmpps.approvedpremisesapi.service.OffenderService + +class Cas1BackfillSpaceBookingsCreatedInDeliusTest { + + private val approvedPremisesRepository = mockk() + + private val seedJob = Cas1BackfillSpaceBookingsCreatedInDelius( + approvedPremisesRepository = approvedPremisesRepository, + cas1DeliusBookingImportRepository = mockk(), + cas1BookingManagementInfoService = mockk(), + environmentService = mockk(), + offenderService = mockk(), + offlineApplicationRepository = mockk(), + spaceBookingRepository = mockk(), + transactionTemplate = mockk(), + ) + + @Test + fun `fails if premise doesn't support space booking`() { + every { approvedPremisesRepository.findByQCode("Q123") } returns + ApprovedPremisesEntityFactory() + .withSupportsSpaceBookings(false) + .withDefaults() + .produce() + + assertThrows { + seedJob.processRow(Cas1CreateMissingReferralsSeedCsvRow("Q123")) + } + } +}