Skip to content

Commit 4769a99

Browse files
* PI-2061 * PI-2061 added feature flag
1 parent dfed991 commit 4769a99

File tree

8 files changed

+233
-2
lines changed

8 files changed

+233
-2
lines changed

projects/manage-offences-and-delius/deploy/database/access.yml

+2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ database:
44
password_key: /manage-offences-and-delius/db-password
55
tables:
66
- r_detailed_offence
7+
- r_offence
78
sequences:
89
- detailed_offence_id_seq
10+
- offence_id_seq
911

1012
audit:
1113
username: ManageOffencesAndDelius

projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class DataLoader(
2929
merge(DataGenerator.COURT_CATEGORY_SET)
3030
merge(DataGenerator.COURT_CATEGORY)
3131
merge(DataGenerator.EXISTING_OFFENCE)
32+
merge(DataGenerator.HL_OFFENCE)
3233
}
3334
}
3435
}

projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt

+39
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@ package uk.gov.justice.digital.hmpps.data.generator
33
import uk.gov.justice.digital.hmpps.entity.DetailedOffence
44
import uk.gov.justice.digital.hmpps.entity.ReferenceData
55
import uk.gov.justice.digital.hmpps.entity.ReferenceDataSet
6+
import uk.gov.justice.digital.hmpps.entity.ReferenceOffence
67
import java.time.LocalDate
78

89
object DataGenerator {
10+
val HL_OFFENCE = generateReferenceOffence(
11+
code = "09100",
12+
mainCategoryCode = "091",
13+
subCategoryCode = "00",
14+
ogrsOffenceCategoryId = 298456347L
15+
)
916
val COURT_CATEGORY_SET = ReferenceDataSet(IdGenerator.getAndIncrement(), "COURT CATEGORY")
1017
val COURT_CATEGORY = ReferenceData(IdGenerator.getAndIncrement(), "CS", "Summary Non-motoring", COURT_CATEGORY_SET)
1118
val EXISTING_OFFENCE = DetailedOffence(
@@ -19,4 +26,36 @@ object DataGenerator {
1926
startDate = LocalDate.of(2006, 5, 12),
2027
endDate = null
2128
)
29+
30+
fun generateReferenceOffence(
31+
code: String,
32+
description: String = "Description of $code",
33+
selectable: Boolean = true,
34+
mainCategoryCode: String,
35+
mainCategoryDescription: String = "Main Category of $code",
36+
mainCategoryAbbreviation: String? = mainCategoryDescription.take(50),
37+
ogrsOffenceCategoryId: Long?,
38+
subCategoryCode: String,
39+
subCategoryDescription: String = "Sub Category of $code",
40+
form20Code: String? = null,
41+
schedule15SexualOffence: Boolean? = false,
42+
schedule15ViolentOffence: Boolean? = false,
43+
childAbduction: Boolean? = false,
44+
id: Long = IdGenerator.getAndIncrement()
45+
) = ReferenceOffence(
46+
code,
47+
description,
48+
selectable,
49+
mainCategoryCode,
50+
mainCategoryDescription,
51+
mainCategoryAbbreviation,
52+
ogrsOffenceCategoryId,
53+
subCategoryCode,
54+
subCategoryDescription,
55+
form20Code,
56+
schedule15SexualOffence,
57+
schedule15ViolentOffence,
58+
childAbduction,
59+
id
60+
)
2261
}

projects/manage-offences-and-delius/src/dev/resources/simulations/__files/offence.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"startDate": "2006-05-12",
88
"endDate": null,
99
"homeOfficeStatsCode": "091/55",
10+
"homeOfficeDescription": "Obstructing a person home office description",
1011
"changedDate": "2010-03-10T16:12:00",
1112
"loadDate": "2023-06-05T10:01:42.867727",
1213
"schedules": null,

projects/manage-offences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
package uk.gov.justice.digital.hmpps
22

3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Assertions
5+
import org.junit.jupiter.api.Assertions.*
36
import org.junit.jupiter.api.Test
7+
import org.mockito.kotlin.atMost
48
import org.mockito.kotlin.verify
9+
import org.mockito.kotlin.whenever
510
import org.springframework.beans.factory.annotation.Autowired
611
import org.springframework.beans.factory.annotation.Value
712
import org.springframework.boot.test.context.SpringBootTest
813
import org.springframework.boot.test.mock.mockito.MockBean
14+
import uk.gov.justice.digital.hmpps.entity.OffenceRepository
15+
import uk.gov.justice.digital.hmpps.flags.FeatureFlags
916
import uk.gov.justice.digital.hmpps.message.Notification
17+
import uk.gov.justice.digital.hmpps.messaging.FF_CREATE_OFFENCE
1018
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
1119
import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader
1220
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
@@ -22,12 +30,34 @@ internal class IntegrationTest {
2230
@MockBean
2331
lateinit var telemetryService: TelemetryService
2432

33+
@MockBean
34+
lateinit var featureFlags: FeatureFlags
35+
36+
@Autowired
37+
lateinit var offenceRepository: OffenceRepository
38+
2539
@Test
2640
fun `update offence code`() {
41+
whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(true)
2742
val notification = Notification(ResourceLoader.event("offence-changed"))
2843

2944
channelManager.getChannel(queueName).publishAndWait(notification)
3045

31-
verify(telemetryService).trackEvent("OffenceCodeUpdated", mapOf("offenceCode" to "AB06001"), mapOf())
46+
verify()
47+
48+
channelManager.getChannel(queueName).publishAndWait(notification)
49+
50+
verify()
51+
}
52+
53+
private fun verify() {
54+
verify(telemetryService, atMost(2)).trackEvent("OffenceCodeUpdated", mapOf("offenceCode" to "AB06001"), mapOf())
55+
56+
val referenceOffence = offenceRepository.findOffenceByCode("09155")
57+
assertNotNull(referenceOffence)
58+
59+
assertThat(referenceOffence?.description).isEqualTo("Obstructing a person home office description")
60+
assertThat(referenceOffence?.mainCategoryCode).isEqualTo("091")
61+
assertThat(referenceOffence?.subCategoryCode).isEqualTo("55")
3262
}
3363
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package uk.gov.justice.digital.hmpps.entity
2+
3+
import jakarta.persistence.*
4+
import jakarta.persistence.GenerationType.SEQUENCE
5+
import org.hibernate.type.YesNoConverter
6+
import org.springframework.data.annotation.CreatedBy
7+
import org.springframework.data.annotation.CreatedDate
8+
import org.springframework.data.annotation.LastModifiedBy
9+
import org.springframework.data.annotation.LastModifiedDate
10+
import org.springframework.data.jpa.domain.support.AuditingEntityListener
11+
import org.springframework.data.jpa.repository.JpaRepository
12+
import java.time.ZonedDateTime
13+
14+
@EntityListeners(AuditingEntityListener::class)
15+
@Entity
16+
@Table(name = "r_offence")
17+
@SequenceGenerator(name = "offence_id_seq", sequenceName = "offence_id_seq", allocationSize = 1)
18+
data class ReferenceOffence(
19+
20+
@Column(columnDefinition = "char(5)")
21+
val code: String,
22+
23+
val description: String,
24+
25+
@Convert(converter = YesNoConverter::class)
26+
val selectable: Boolean?,
27+
28+
@Column(columnDefinition = "char(3)")
29+
val mainCategoryCode: String,
30+
31+
val mainCategoryDescription: String,
32+
val mainCategoryAbbreviation: String?,
33+
34+
val ogrsOffenceCategoryId: Long?,
35+
36+
@Column(columnDefinition = "char(2)")
37+
val subCategoryCode: String,
38+
39+
val subCategoryDescription: String,
40+
41+
@Column(name = "form_20_code")
42+
val form20Code: String?,
43+
44+
@Convert(converter = YesNoConverter::class)
45+
@Column(name = "schedule15_sexual_offence")
46+
val schedule15SexualOffence: Boolean?,
47+
48+
@Convert(converter = YesNoConverter::class)
49+
@Column(name = "schedule15_violent_offence")
50+
val schedule15ViolentOffence: Boolean?,
51+
52+
@Convert(converter = YesNoConverter::class)
53+
val childAbduction: Boolean?,
54+
55+
@Id
56+
@GeneratedValue(strategy = SEQUENCE, generator = "offence_id_seq")
57+
@Column(name = "offence_id")
58+
val id: Long = 0
59+
) {
60+
61+
@Column
62+
val partitionAreaId: Long = 0
63+
64+
@Version
65+
var rowVersion: Long = 0
66+
67+
@CreatedDate
68+
@Column(name = "created_datetime")
69+
var created: ZonedDateTime = ZonedDateTime.now()
70+
71+
@CreatedBy
72+
@Column(name = "created_by_user_id")
73+
var createdBy: Long = 0
74+
75+
@LastModifiedDate
76+
@Column(name = "last_updated_datetime")
77+
var lastModified: ZonedDateTime = ZonedDateTime.now()
78+
79+
@LastModifiedBy
80+
@Column(name = "last_updated_user_id")
81+
var lastModifiedBy: Long = 0
82+
}
83+
84+
interface OffenceRepository : JpaRepository<ReferenceOffence, Long> {
85+
fun findOffenceByCode(code: String): ReferenceOffence?
86+
}

projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt

+59-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package uk.gov.justice.digital.hmpps.messaging
22

33
import org.springframework.stereotype.Component
4+
import org.springframework.transaction.annotation.Transactional
45
import uk.gov.justice.digital.hmpps.client.ManageOffencesClient
56
import uk.gov.justice.digital.hmpps.client.Offence
67
import uk.gov.justice.digital.hmpps.converter.NotificationConverter
78
import uk.gov.justice.digital.hmpps.entity.DetailedOffence
9+
import uk.gov.justice.digital.hmpps.entity.OffenceRepository
10+
import uk.gov.justice.digital.hmpps.entity.ReferenceOffence
811
import uk.gov.justice.digital.hmpps.exception.NotFoundException
12+
import uk.gov.justice.digital.hmpps.flags.FeatureFlags
913
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
1014
import uk.gov.justice.digital.hmpps.message.Notification
1115
import uk.gov.justice.digital.hmpps.repository.DetailedOffenceRepository
@@ -14,18 +18,26 @@ import uk.gov.justice.digital.hmpps.repository.findCourtCategory
1418
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService
1519
import uk.gov.justice.digital.hmpps.telemetry.notificationReceived
1620

21+
const val FF_CREATE_OFFENCE = "manage-offences-create-offence"
22+
1723
@Component
1824
class Handler(
1925
override val converter: NotificationConverter<HmppsDomainEvent>,
2026
private val telemetryService: TelemetryService,
2127
private val manageOffencesClient: ManageOffencesClient,
2228
private val detailedOffenceRepository: DetailedOffenceRepository,
23-
private val referenceDataRepository: ReferenceDataRepository
29+
private val offenceRepository: OffenceRepository,
30+
private val referenceDataRepository: ReferenceDataRepository,
31+
private val featureFlags: FeatureFlags
2432
) : NotificationHandler<HmppsDomainEvent> {
2533

34+
@Transactional
2635
override fun handle(notification: Notification<HmppsDomainEvent>) {
2736
telemetryService.notificationReceived(notification)
2837
val offence = manageOffencesClient.getOffence(notification.message.offenceCode)
38+
if (featureFlags.enabled(FF_CREATE_OFFENCE)) {
39+
offence.createOrMerge()
40+
}
2941
val existingEntity = detailedOffenceRepository.findByCode(offence.code)
3042
detailedOffenceRepository.save(existingEntity.mergeWith(offence.newEntity))
3143
telemetryService.trackEvent(
@@ -57,6 +69,52 @@ class Handler(
5769
legislation = newEntity.legislation,
5870
category = newEntity.category
5971
) ?: newEntity
72+
73+
private fun Offence.createOrMerge() {
74+
if (homeOfficeStatsCode != null && homeOfficeDescription != null) {
75+
val highLevelOffence = checkNotNull(offenceRepository.findOffenceByCode(highLevelCode!!)) {
76+
"High Level Offence not found: $highLevelCode"
77+
}
78+
79+
val offence = offenceRepository.findOffenceByCode(homeOfficeCode).mergeWith(asReference(highLevelOffence))
80+
offenceRepository.save(offence)
81+
}
82+
}
6083
}
6184

6285
val HmppsDomainEvent.offenceCode get() = additionalInformation["offenceCode"] as String
86+
87+
val Offence.mainCategoryCode get() = homeOfficeStatsCode?.take(3)
88+
val Offence.subCategoryCode get() = homeOfficeStatsCode?.takeLast(2)
89+
val Offence.highLevelCode get() = mainCategoryCode?.let { it + "00" }
90+
val Offence.homeOfficeCode get() = mainCategoryCode + subCategoryCode
91+
fun Offence.asReference(highLevelOffence: ReferenceOffence) = ReferenceOffence(
92+
code = homeOfficeCode,
93+
description = homeOfficeDescription!!,
94+
mainCategoryCode = mainCategoryCode!!,
95+
selectable = false,
96+
mainCategoryDescription = highLevelOffence.description,
97+
mainCategoryAbbreviation = highLevelOffence.description.take(50),
98+
ogrsOffenceCategoryId = highLevelOffence.ogrsOffenceCategoryId,
99+
subCategoryCode = subCategoryCode!!,
100+
subCategoryDescription = "$homeOfficeDescription - $subCategoryCode",
101+
form20Code = highLevelOffence.form20Code,
102+
childAbduction = null,
103+
schedule15SexualOffence = null,
104+
schedule15ViolentOffence = null
105+
)
106+
107+
fun ReferenceOffence?.mergeWith(referenceOffence: ReferenceOffence) = this?.copy(
108+
code = code,
109+
description = description,
110+
mainCategoryCode = mainCategoryCode,
111+
mainCategoryDescription = mainCategoryDescription,
112+
mainCategoryAbbreviation = mainCategoryAbbreviation,
113+
ogrsOffenceCategoryId = ogrsOffenceCategoryId,
114+
subCategoryCode = subCategoryCode,
115+
subCategoryDescription = subCategoryDescription,
116+
form20Code = form20Code,
117+
schedule15SexualOffence = schedule15SexualOffence,
118+
schedule15ViolentOffence = schedule15ViolentOffence,
119+
childAbduction = childAbduction
120+
) ?: referenceOffence

projects/manage-offences-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package uk.gov.justice.digital.hmpps.messaging
22

33
import org.hamcrest.MatcherAssert.assertThat
44
import org.hamcrest.Matchers.equalTo
5+
import org.junit.jupiter.api.BeforeEach
56
import org.junit.jupiter.api.Test
67
import org.junit.jupiter.api.assertThrows
78
import org.junit.jupiter.api.extension.ExtendWith
@@ -16,7 +17,9 @@ import uk.gov.justice.digital.hmpps.client.Offence
1617
import uk.gov.justice.digital.hmpps.converter.NotificationConverter
1718
import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.COURT_CATEGORY
1819
import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.EXISTING_OFFENCE
20+
import uk.gov.justice.digital.hmpps.entity.OffenceRepository
1921
import uk.gov.justice.digital.hmpps.exception.NotFoundException
22+
import uk.gov.justice.digital.hmpps.flags.FeatureFlags
2023
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
2124
import uk.gov.justice.digital.hmpps.message.Notification
2225
import uk.gov.justice.digital.hmpps.repository.DetailedOffenceRepository
@@ -40,12 +43,23 @@ internal class HandlerTest {
4043
@Mock
4144
lateinit var detailedOffenceRepository: DetailedOffenceRepository
4245

46+
@Mock
47+
lateinit var offenceRepository: OffenceRepository
48+
4349
@Mock
4450
lateinit var referenceDataRepository: ReferenceDataRepository
4551

52+
@Mock
53+
lateinit var featureFlags: FeatureFlags
54+
4655
@InjectMocks
4756
lateinit var handler: Handler
4857

58+
@BeforeEach
59+
fun setup() {
60+
whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(false)
61+
}
62+
4963
@Test
5064
fun `missing reference data is thrown`() {
5165
val notification = Notification(ResourceLoader.event("offence-changed"))

0 commit comments

Comments
 (0)