Skip to content

Commit f866099

Browse files
Update single auth occurrence handling
1 parent f708ff3 commit f866099

File tree

6 files changed

+100
-5
lines changed

6 files changed

+100
-5
lines changed

src/main/kotlin/uk/gov/justice/digital/hmpps/externalmovementsapi/domain/tap/occurrence/TemporaryAbsenceOccurrence.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,11 @@ class TemporaryAbsenceOccurrence(
365365
this.dpsOnly = false
366366
}
367367

368+
fun makeDpsOnly() = apply {
369+
dpsOnly = true
370+
legacyId = null
371+
}
372+
368373
private fun movementStatus(): OccurrenceStatus.Code? = movements.takeIf { it.isNotEmpty() }
369374
?.map { it.direction }?.let {
370375
if (it.contains(TemporaryAbsenceMovement.Direction.IN)) {

src/main/kotlin/uk/gov/justice/digital/hmpps/externalmovementsapi/service/TapAuthorisationModifications.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ class TapAuthorisationModifications(
7474
throw ConflictException("Temporary absence authorisation not approved")
7575
} else {
7676
authorisation.cancel(action, rdSupplier)
77-
authorisation.affectedOccurrences().forEach { it.cancel(CancelOccurrence(), rdSupplier) }
77+
authorisation.affectedOccurrences().forEach {
78+
if (!authorisation.repeat) {
79+
it.makeDpsOnly()
80+
}
81+
it.cancel(CancelOccurrence(), rdSupplier)
82+
}
7883
}
7984

8085
is ChangeAuthorisationAccompaniment -> {
@@ -125,6 +130,9 @@ class TapAuthorisationModifications(
125130

126131
private fun TemporaryAbsenceAuthorisation.updateOccurrenceStatus() {
127132
affectedOccurrences().forEach {
133+
if (!repeat && status.code != APPROVED.name) {
134+
it.makeDpsOnly()
135+
}
128136
it.calculateStatus { statusCode -> occurrenceStatusRepository.getByCode(statusCode) }
129137
}
130138
}

src/main/kotlin/uk/gov/justice/digital/hmpps/externalmovementsapi/sync/internal/SyncTapAuthorisation.kt

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.referencedata.Re
1414
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.ReferenceDataPaths
1515
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.authorisation.TemporaryAbsenceAuthorisation
1616
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.authorisation.TemporaryAbsenceAuthorisationRepository
17+
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.occurrence.TemporaryAbsenceOccurrence
1718
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.occurrence.TemporaryAbsenceOccurrenceRepository
1819
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.referencedata.AccompaniedBy
1920
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.tap.referencedata.AuthorisationStatus
@@ -41,14 +42,19 @@ import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.authorisa
4142
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.authorisation.DenyAuthorisation
4243
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.authorisation.ExpireAuthorisation
4344
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.authorisation.RecategoriseAuthorisation
45+
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.occurrence.ChangeOccurrenceAccompaniment
46+
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.occurrence.ChangeOccurrenceComments
4447
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.occurrence.ChangeOccurrenceLocation
48+
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.occurrence.ChangeOccurrenceTransport
49+
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.occurrence.RecategoriseOccurrence
4550
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.occurrence.RescheduleOccurrence
4651
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.location.Location
4752
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.location.isNullOrEmpty
4853
import uk.gov.justice.digital.hmpps.externalmovementsapi.service.person.PersonSummaryService
4954
import uk.gov.justice.digital.hmpps.externalmovementsapi.sync.write.SyncResponse
5055
import uk.gov.justice.digital.hmpps.externalmovementsapi.sync.write.TapAuthorisation
5156
import java.time.LocalDate.now
57+
import java.time.LocalDateTime.of
5258
import java.util.UUID
5359

5460
@Transactional
@@ -170,9 +176,7 @@ class SyncTapAuthorisation(
170176
occurrenceRepository.delete(occ)
171177
null
172178
} else {
173-
occ.reschedule(RescheduleOccurrence(start.atTime(schedule.startTime), end.atTime(schedule.returnTime)))
174-
request.location?.also { occ.applyLocation(ChangeOccurrenceLocation(it)) }
175-
occ.calculateStatus { rdPaths.getReferenceData(OccurrenceStatus::class, it) as OccurrenceStatus }
179+
occ.updateFrom(this, request, rdPaths)
176180
}
177181
} ?: createOccurrence(objectMapper, rdPaths)
178182
}
@@ -187,6 +191,27 @@ class SyncTapAuthorisation(
187191
}?.also(occurrenceRepository::save)
188192
}
189193

194+
private fun TemporaryAbsenceOccurrence.updateFrom(
195+
authorisation: TemporaryAbsenceAuthorisation,
196+
request: TapAuthorisation,
197+
rdPaths: ReferenceDataPaths,
198+
) = apply {
199+
authorisationPersonAndPrison(authorisation)
200+
applyAbsenceCategorisation(
201+
RecategoriseOccurrence(absenceType?.code, absenceSubType?.code, absenceReasonCategory?.code, absenceReason.code),
202+
rdPaths::getReferenceData,
203+
)
204+
reschedule(RescheduleOccurrence(of(request.start, request.startTime), of(request.end, request.endTime)))
205+
applyLocation(ChangeOccurrenceLocation(request.location ?: Location.empty()))
206+
applyAccompaniment(ChangeOccurrenceAccompaniment(request.accompaniedByCode), rdPaths::getReferenceData)
207+
applyTransport(ChangeOccurrenceTransport(request.transportCode), rdPaths::getReferenceData)
208+
applyComments(ChangeOccurrenceComments(request.comments))
209+
makeDpsOnly()
210+
calculateStatus {
211+
rdPaths.getReferenceData(OccurrenceStatus::class, it) as OccurrenceStatus
212+
}
213+
}
214+
190215
private fun TemporaryAbsenceAuthorisation.applyAbsenceCategorisation(
191216
request: TapAuthorisation,
192217
rdPaths: ReferenceDataPaths,

src/main/kotlin/uk/gov/justice/digital/hmpps/externalmovementsapi/sync/migrate/MigrateTapRequest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package uk.gov.justice.digital.hmpps.externalmovementsapi.sync.migrate
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore
34
import io.swagger.v3.oas.annotations.media.Schema
45
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.referencedata.ReferenceDataDomain.Code.ABSENCE_REASON
56
import uk.gov.justice.digital.hmpps.externalmovementsapi.domain.referencedata.ReferenceDataDomain.Code.ABSENCE_SUB_TYPE
@@ -28,6 +29,7 @@ data class MigrateTapRequest(
2829
val temporaryAbsences: List<TapAuthorisation>,
2930
val unscheduledMovements: List<TapMovement>,
3031
) {
32+
@JsonIgnore
3133
fun isEmpty(): Boolean = temporaryAbsences.isEmpty() && unscheduledMovements.isEmpty()
3234
}
3335

src/test/kotlin/uk/gov/justice/digital/hmpps/externalmovementsapi/integration/sync/SyncTapAuthorisationIntTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ class SyncTapAuthorisationIntTest(
551551
start = existing.start.atTime(9, 0),
552552
end = existing.end.atTime(17, 0),
553553
location = Location.empty(),
554+
comments = existing.comments,
554555
dpsOnly = true,
555556
),
556557
)

src/test/kotlin/uk/gov/justice/digital/hmpps/externalmovementsapi/integration/tap/authorisation/CancelTapAuthorisationIntTest.kt

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import uk.gov.justice.digital.hmpps.externalmovementsapi.integration.config.Temp
3131
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.AuditHistory
3232
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.AuditedAction
3333
import uk.gov.justice.digital.hmpps.externalmovementsapi.model.actions.authorisation.CancelAuthorisation
34+
import java.time.LocalDate
3435
import java.time.LocalDateTime
3536
import java.util.UUID
3637

@@ -77,7 +78,7 @@ class CancelTapAuthorisationIntTest(
7778

7879
@Test
7980
fun `200 ok - authorisation cancelled`() {
80-
val auth = givenTemporaryAbsenceAuthorisation(temporaryAbsenceAuthorisation())
81+
val auth = givenTemporaryAbsenceAuthorisation(temporaryAbsenceAuthorisation(repeat = true))
8182
val pastOccurrence = givenTemporaryAbsenceOccurrence(
8283
temporaryAbsenceOccurrence(
8384
auth,
@@ -99,8 +100,10 @@ class CancelTapAuthorisationIntTest(
99100
assertThat(saved.status.code).isEqualTo(AuthorisationStatus.Code.CANCELLED.name)
100101
val previousAbsence = requireNotNull(findTemporaryAbsenceOccurrence(pastOccurrence.id))
101102
assertThat(previousAbsence.status.code).isEqualTo(OccurrenceStatus.Code.EXPIRED.name)
103+
assertThat(previousAbsence.dpsOnly).isFalse
102104
val absence = requireNotNull(findTemporaryAbsenceOccurrence(occurrence.id))
103105
assertThat(absence.status.code).isEqualTo(OccurrenceStatus.Code.CANCELLED.name)
106+
assertThat(absence.dpsOnly).isFalse
104107

105108
verifyAudit(
106109
saved,
@@ -122,6 +125,57 @@ class CancelTapAuthorisationIntTest(
122125
)
123126
}
124127

128+
@Test
129+
fun `200 ok - single authorisation cancelled`() {
130+
val auth = givenTemporaryAbsenceAuthorisation(
131+
temporaryAbsenceAuthorisation(
132+
repeat = false,
133+
start = LocalDate.now().plusDays(1),
134+
end = LocalDate.now().plusDays(1),
135+
),
136+
)
137+
val occ = givenTemporaryAbsenceOccurrence(
138+
temporaryAbsenceOccurrence(
139+
auth,
140+
start = LocalDateTime.now().plusDays(1),
141+
end = LocalDateTime.now().plusDays(1),
142+
),
143+
)
144+
val request = cancelAuthorisationRequest(reason = "Occurrence is delete by nomis")
145+
146+
val res = cancelAuthorisation(auth.id, request).successResponse<AuditHistory>().content.single()
147+
assertThat(res.domainEvents).containsExactly(TemporaryAbsenceAuthorisationCancelled.EVENT_TYPE)
148+
assertThat(res.reason).isEqualTo(request.reason)
149+
assertThat(res.changes).containsExactly(
150+
AuditedAction.Change("status", "Approved", "Cancelled"),
151+
)
152+
153+
val saved = requireNotNull(findTemporaryAbsenceAuthorisation(auth.id))
154+
assertThat(saved.status.code).isEqualTo(AuthorisationStatus.Code.CANCELLED.name)
155+
val occurrence = requireNotNull(findTemporaryAbsenceOccurrence(occ.id))
156+
assertThat(occurrence.status.code).isEqualTo(OccurrenceStatus.Code.CANCELLED.name)
157+
assertThat(occurrence.dpsOnly).isTrue
158+
159+
verifyAudit(
160+
saved,
161+
RevisionType.MOD,
162+
setOf(
163+
TemporaryAbsenceAuthorisation::class.simpleName!!,
164+
TemporaryAbsenceOccurrence::class.simpleName!!,
165+
HmppsDomainEvent::class.simpleName!!,
166+
),
167+
ExternalMovementContext.get().copy(username = DEFAULT_USERNAME, reason = request.reason),
168+
)
169+
170+
verifyEventPublications(
171+
saved,
172+
setOf(
173+
TemporaryAbsenceAuthorisationCancelled(auth.person.identifier, auth.id).publication(auth.id),
174+
TemporaryAbsenceCancelled(auth.person.identifier, occurrence.id).publication(occurrence.id) { false },
175+
),
176+
)
177+
}
178+
125179
private fun cancelAuthorisationRequest(
126180
reason: String? = "Evidence justifying the approval",
127181
) = CancelAuthorisation(reason)

0 commit comments

Comments
 (0)