Skip to content

Commit

Permalink
Add batch job to load referral status (#2002)
Browse files Browse the repository at this point in the history
* Add batch job to load referral status

* Remove redundant job definition files following apply to prod

---------

Co-authored-by: Andrew Hodgson <[email protected]>
  • Loading branch information
marcocolluramoj and awhodgson256 authored Aug 16, 2024
1 parent d7c2906 commit fbd4d92
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: load-end-of-sentence
name: load-status
spec:
schedule: "0 2 * * *"
suspend: true
Expand All @@ -11,8 +11,8 @@ spec:
spec:
restartPolicy: "Never"
containers:
- name: load-send-of-sentence
- name: load-status
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: Always
args: ["--jobName=loadEndOfSentenceJob"]
args: ["--jobName=loadStatusJob"]
{{- include "deployment.envs" . | nindent 14 }}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.transferreferrals
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import org.springframework.batch.core.Job
import org.springframework.batch.core.Step
Expand All @@ -17,35 +17,35 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.reporting.Timestam

@Configuration
@EnableTransactionManagement
class LoadEndOfSentenceJobConfiguration(
class LoadStatusJobConfiguration(
private val jobRepository: JobRepository,
private val listener: LoadEndOfSentenceJobListener,
private val listener: LoadStatusJobListener,
private val onStartupJobLauncherFactory: OnStartupJobLauncherFactory,
@Qualifier("batchJobBuilderFactory") private val jobBuilderFactory: JobBuilderFactory,
@Qualifier("batchStepBuilderFactory") private val stepBuilderFactory: StepBuilderFactory,
) {
@Bean
fun loadEndOfSentenceJobLauncher(loadEndOfSentenceJob: Job): ApplicationRunner {
return onStartupJobLauncherFactory.makeBatchLauncher(loadEndOfSentenceJob)
fun loadStatusJobLauncher(loadStatusJob: Job): ApplicationRunner {
return onStartupJobLauncherFactory.makeBatchLauncher(loadStatusJob)
}

@Bean
fun loadEndOfSentenceJob(loadEndOfSentenceStep: Step): Job {
return jobBuilderFactory.get("loadEndOfSentenceJob")
fun loadStatusJob(loadStatusStep: Step): Job {
return jobBuilderFactory.get("loadStatusJob")
.incrementer(TimestampIncrementer())
.listener(listener)
.start(loadEndOfSentenceStep)
.start(loadStatusStep)
.build()
}

@Bean
fun loadEndOfSentenceStep(
reader: LoadEndOfSentenceReader,
processor: LoadEndOfSentenceProcessor,
writer: LoadEndOfSentenceWriter,
fun loadStatusStep(
reader: LoadStatusReader,
processor: LoadStatusProcessor,
writer: LoadStatusWriter,
transactionManager: PlatformTransactionManager,
): Step {
return stepBuilderFactory.get("loadEndOfSentenceStep")
return stepBuilderFactory.get("loadStatusStep")
.chunk<Referral, Referral>(5000, transactionManager)
.reader(reader)
.processor(processor)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.transferreferrals
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import mu.KLogging
import net.logstash.logback.argument.StructuredArguments.kv
Expand All @@ -8,7 +8,7 @@ import org.springframework.batch.core.JobExecutionListener
import org.springframework.stereotype.Component

@Component
class LoadEndOfSentenceJobListener : JobExecutionListener {
class LoadStatusJobListener : JobExecutionListener {
companion object : KLogging()

override fun beforeJob(jobExecution: JobExecution) {
Expand All @@ -24,7 +24,7 @@ class LoadEndOfSentenceJobListener : JobExecutionListener {

else -> {
logger.warn(
"unexpected status encountered for load end of sentence {} {}",
"unexpected status encountered for load status {} {}",
kv("status", jobExecution.status),
kv("exitDescription", jobExecution.exitStatus.exitDescription),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import mu.KLogging
import net.logstash.logback.argument.StructuredArguments.kv
import org.springframework.batch.core.configuration.annotation.JobScope
import org.springframework.batch.item.ItemProcessor
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.DeliverySessionRepository
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.ReferralRepository

@Component
@JobScope
class LoadStatusProcessor(
private val deliverySessionRepository: DeliverySessionRepository,
private val referralRepository: ReferralRepository,
) : ItemProcessor<Referral, Referral> {
companion object : KLogging()

override fun process(referral: Referral): Referral {
logger.info("processing referral {} for status", kv("referralId", referral.id))
return updateReferralStatus(referral)
}

fun updateReferralStatus(referral: Referral): Referral {
val status = if (deliveredFirstSubstantiveAppointment(referral)) Status.POST_ICA else Status.PRE_ICA
referral.status = status
return referralRepository.save(referral)
}

private fun countSessionsAttended(referral: Referral): Int {
return deliverySessionRepository.countNumberOfAttendedSessions(referral.id)
}

private fun deliveredFirstSubstantiveAppointment(referral: Referral): Boolean {
return countSessionsAttended(referral) > 0
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.transferreferrals
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import org.hibernate.SessionFactory
import org.springframework.batch.core.configuration.annotation.JobScope
Expand All @@ -8,14 +8,14 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referra

@Component
@JobScope
class LoadEndOfSentenceReader(
class LoadStatusReader(
sessionFactory: SessionFactory,
) : HibernateCursorItemReader<Referral>() {
init {
this.setName("loadEndOfSentenceReader")
this.setName("loadStatusReader")
this.setSessionFactory(sessionFactory)
this.setQueryString(
"SELECT r FROM Referral r where r.relevantSentenceEndDate is null",
"SELECT r FROM Referral r where r.status is null",
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.transferreferrals
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import org.springframework.batch.item.Chunk
import org.springframework.batch.item.ItemWriter
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral

@Component
class LoadEndOfSentenceWriter : ItemWriter<Referral?> {
class LoadStatusWriter : ItemWriter<Referral?> {
override fun write(chunk: Chunk<out Referral?>) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referra
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.SelectedDesiredOutcomesMapping
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceCategory
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceUserData
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.SupplierAssessment
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.WithdrawalReason
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.ActionPlanRepository
Expand Down Expand Up @@ -469,6 +470,7 @@ class SetupAssistant(
expectedReleaseDate: LocalDate? = null,
probationPractitionerDetails: ProbationPractitionerDetails? = null,
relevantSentenceEndDate: LocalDate? = null,
status: Status? = null,
): Referral {
createDraftReferral(
id = id,
Expand All @@ -490,6 +492,7 @@ class SetupAssistant(
interpreterLanguage = interpreterLanguage,
probationPractitionerDetails = probationPractitionerDetails,
relevantSentenceEndDate = relevantSentenceEndDate,
status = status,
)

referral = referralRepository.save(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.AdditionalAnswers
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.DeliverySessionRepository
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.ReferralRepository
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.ReferralFactory

internal class LoadStatusProcessorTest {

private val referralRepository = mock<ReferralRepository>()
private val deliverySessionRepository = mock<DeliverySessionRepository>()
private val processor = LoadStatusProcessor(
deliverySessionRepository,
referralRepository,
)

private val referralFactory = ReferralFactory()

private val referral = referralFactory.createSent(status = null)

@BeforeEach
fun setup() {
whenever(referralRepository.save(any())).thenAnswer(AdditionalAnswers.returnsFirstArg<Referral>())
}

@Test
fun `referral status is set to PRE_ICA if first substantive appointment not delivered`() {
whenever(deliverySessionRepository.countNumberOfAttendedSessions(referral.id)).thenReturn(0)
val result = processor.process(referral)
assertThat(result.status).isEqualTo(Status.PRE_ICA)
verify(referralRepository).save(referral)
}

@Test
fun `referral status is set to POST_ICA if first substantive appointment is delivered`() {
whenever(deliverySessionRepository.countNumberOfAttendedSessions(referral.id)).thenReturn(1)
val result = processor.process(referral)
assertThat(result.status).isEqualTo(Status.POST_ICA)
verify(referralRepository).save(referral)
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadendofsentence
package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.loadstatus

import org.assertj.core.api.Assertions.assertThat
import org.hibernate.SessionFactory
import org.junit.jupiter.api.Test
import org.springframework.batch.item.ExecutionContext
import org.springframework.beans.factory.annotation.Autowired
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.integration.IntegrationTestBase
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jobs.oneoff.transferreferrals.LoadEndOfSentenceReader
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral
import java.time.LocalDate
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status

internal class LoadEndOfSentenceReaderTest
internal class LoadStatusReaderTest
@Autowired constructor(
sessionFactory: SessionFactory,
) : IntegrationTestBase() {
private val reader = LoadEndOfSentenceReader(sessionFactory)
private val reader = LoadStatusReader(sessionFactory)

fun createPopulatedReferral(): Referral {
return setupAssistant.createSentReferral(relevantSentenceEndDate = LocalDate.now())
return setupAssistant.createSentReferral(status = Status.PRE_ICA)
}

fun createUnpopulatedReferral(): Referral {
return setupAssistant.createSentReferral(relevantSentenceEndDate = null)
return setupAssistant.createSentReferral(status = null)
}

@Test
fun `skips referral that has a valid relevantSentenceEndDate`() {
fun `skips referral that has a status`() {
val targetReferral = createPopulatedReferral()
reader.open(ExecutionContext())
val result = reader.read()
assertThat(result).isNull()
}

@Test
fun `finds referral that has a null relevantSentenceEndDate`() {
fun `finds referral that has a null status`() {
val targetReferral = createUnpopulatedReferral()
reader.open(ExecutionContext())
assertThat(reader.read()?.id).isEqualTo(targetReferral.id)
Expand Down
Loading

0 comments on commit fbd4d92

Please sign in to comment.