Skip to content

Commit

Permalink
PI-2161: Created post endpoint for /nomis-case-note/{crn} (#3828)
Browse files Browse the repository at this point in the history
* PI-2161: Created post endpoint for /nomis-case-note/{crn}

* PI-2161: Moved staff code generator to common library
  • Loading branch information
pmcphee77 authored May 24, 2024
1 parent 4987200 commit cbb862c
Show file tree
Hide file tree
Showing 54 changed files with 1,138 additions and 371 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package uk.gov.justice.digital.hmpps.exception

open class InvalidRequestException(message: String) : RuntimeException(message) {
constructor(
fieldName: String,
value: Any
) : this("Invalid $fieldName of $value sent in payload")
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package uk.gov.justice.digital.hmpps.advice

import org.springframework.http.HttpStatus.BAD_REQUEST
import org.springframework.http.HttpStatus.CONFLICT
import org.springframework.http.HttpStatus.NOT_FOUND
import org.springframework.http.HttpStatus.*
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import uk.gov.justice.digital.hmpps.exception.ConflictException
import uk.gov.justice.digital.hmpps.exception.InvalidRequestException
import uk.gov.justice.digital.hmpps.exception.NotFoundException

@RestControllerAdvice(basePackages = ["uk.gov.justice.digital.hmpps"])
Expand All @@ -32,4 +31,9 @@ class ControllerAdvice {
fields = e.bindingResult.fieldErrors.map { FieldError(it.code, it.defaultMessage, it.field) }
)
)

@ExceptionHandler(InvalidRequestException::class)
fun handleInvalidRequest(e: InvalidRequestException) = ResponseEntity
.status(BAD_REQUEST)
.body(ErrorResponse(status = BAD_REQUEST.value(), message = e.message))
}
21 changes: 21 additions & 0 deletions libs/prison-staff/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import uk.gov.justice.digital.hmpps.extensions.ClassPathExtension

dependencies {
compileOnly("org.springframework.boot:spring-boot-starter-data-jpa")
implementation(project(":libs:commons"))
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-validation")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-starter-data-jpa")
testImplementation(libs.bundles.mockito)
}

configure<ClassPathExtension> {
jacocoExclusions = listOf(
"**/exception/**",
"**/config/**",
"**/entity**",
"**/logging/**"
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package uk.gov.justice.digital.hmpps.entity

import jakarta.persistence.*
import org.springframework.data.annotation.CreatedBy
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedBy
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.ZonedDateTime

@EntityListeners(AuditingEntityListener::class)
@Entity(name = "PrisonStaff")
@Table(name = "staff")
class PrisonStaff(

@Id
@Column(name = "staff_id")
@SequenceGenerator(name = "staff_id_seq", sequenceName = "staff_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "staff_id_seq")
val id: Long = 0,

@Column(name = "forename")
val forename: String,

@Column(name = "surname")
val surname: String,

@Column(name = "officer_code", columnDefinition = "char(7)")
val code: String,

@Column(name = "probation_area_id")
val probationAreaId: Long,

@Column(name = "start_date", updatable = false)
val startDate: ZonedDateTime = ZonedDateTime.now(),

@CreatedDate
@Column(name = "created_datetime", updatable = false)
val createdDateTime: ZonedDateTime = ZonedDateTime.now(),

@LastModifiedDate
@Column(name = "last_updated_datetime")
val lastModifiedDate: ZonedDateTime = ZonedDateTime.now(),

@Column(name = "private", columnDefinition = "NUMBER", nullable = false)
var privateStaff: Boolean = false,

@CreatedBy
@Column(name = "created_by_user_id", updatable = false)
var createdByUserId: Long = 0,

@LastModifiedBy
@Column(name = "last_updated_user_id")
var lastModifiedUserId: Long = 0,

@Version
@Column(name = "row_version")
val version: Long = 0
) {
fun isUnallocated() = code.endsWith("U")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package uk.gov.justice.digital.hmpps.entity

import jakarta.persistence.*
import org.springframework.data.annotation.CreatedBy
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedBy
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.io.Serializable
import java.time.ZonedDateTime

@EntityListeners(AuditingEntityListener::class)
@Entity
@Table(name = "staff_team")
@IdClass(StaffTeamId::class)
class PrisonStaffTeam(

@Id
@Column(name = "staff_id")
val staffId: Long,

@Id
@Column(name = "team_id")
val teamId: Long,

@CreatedBy
@Column(name = "created_by_user_id", updatable = false)
var createdByUserId: Long = 0,

@LastModifiedBy
@Column(name = "last_updated_user_id")
val lastModifiedUserId: Long = 0,

@CreatedDate
@Column(name = "created_datetime", updatable = false)
val createdDateTime: ZonedDateTime = ZonedDateTime.now(),

@LastModifiedDate
@Column(name = "last_updated_datetime")
val lastModifiedDate: ZonedDateTime = ZonedDateTime.now(),

@Version
@Column(name = "row_version")
val version: Long = 0
)

data class StaffTeamId(val staffId: Long = 0, val teamId: Long = 0) : Serializable
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package uk.gov.justice.digital.hmpps.entity

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.Table
import org.hibernate.annotations.Immutable

@Immutable
@Entity(name = "PrisonTeam")
@Table(name = "team")
class PrisonTeam(

@Id
@Column(name = "team_id")
val id: Long,

@Column(name = "code", columnDefinition = "char(6)")
val code: String

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package uk.gov.justice.digital.hmpps.entity

import jakarta.persistence.*
import org.hibernate.annotations.Immutable

@Immutable
@Entity(name = "Provider")
@Table(name = "probation_area")
class Provider(
@Id
@Column(name = "probation_area_id")
val id: Long,

@Column(name = "code", columnDefinition = "char(3)")
val code: String,

@OneToOne
@JoinColumn(
name = "institution_id",
referencedColumnName = "institution_id",
updatable = false
)
val institution: Prison? = null
)

@Immutable
@Entity(name = "Prison")
@Table(name = "r_institution")
class Prison(
@Id
@Column(name = "institution_id")
val id: Long,

@Column(name = "nomis_cde_code")
val nomisCode: String

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package uk.gov.justice.digital.hmpps.exceptions

class InvalidEstablishmentCodeException(establishmentCode: String) :
RuntimeException("Invalid establishment: $establishmentCode")
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package uk.gov.justice.digital.hmpps.exceptions

class StaffCodeExhaustedException(code: String) : RuntimeException("Officer codes exhausted for: $code")
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package uk.gov.justice.digital.hmpps.model

import jakarta.validation.constraints.NotBlank

data class StaffName(@NotBlank val forename: String, @NotBlank val surname: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package uk.gov.justice.digital.hmpps.repository

import org.springframework.data.jpa.repository.JpaRepository
import uk.gov.justice.digital.hmpps.entity.Provider

interface PrisonProbationAreaRepository : JpaRepository<Provider, Long> {
fun findByInstitutionNomisCode(nomisCode: String): Provider?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package uk.gov.justice.digital.hmpps.repository

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import uk.gov.justice.digital.hmpps.entity.PrisonStaff
import uk.gov.justice.digital.hmpps.exception.NotFoundException

interface PrisonStaffRepository : JpaRepository<PrisonStaff, Long> {
fun findTopByProbationAreaIdAndForenameIgnoreCaseAndSurnameIgnoreCase(
probationAreaId: Long,
forename: String,
surname: String
): PrisonStaff?

@Query(
"""
select officer_code from staff
where regexp_like(officer_code, ?1, 'i')
order by officer_code desc
fetch next 1 rows only
""",
nativeQuery = true
)
fun getLatestStaffReference(regex: String): String?

fun findByCode(code: String): PrisonStaff?
}

fun PrisonStaffRepository.getByCode(code: String) =
findByCode(code) ?: throw NotFoundException("Staff", "code", code)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package uk.gov.justice.digital.hmpps.repository

import org.springframework.data.jpa.repository.JpaRepository
import uk.gov.justice.digital.hmpps.entity.PrisonStaffTeam
import uk.gov.justice.digital.hmpps.entity.StaffTeamId

interface PrisonStaffTeamRepository : JpaRepository<PrisonStaffTeam, StaffTeamId>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package uk.gov.justice.digital.hmpps.repository

import org.springframework.data.jpa.repository.JpaRepository
import uk.gov.justice.digital.hmpps.entity.PrisonTeam

interface PrisonTeamRepository : JpaRepository<PrisonTeam, Long> {
fun findByCode(code: String): PrisonTeam?
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package uk.gov.justice.digital.hmpps.integrations.delius.service
package uk.gov.justice.digital.hmpps.service

import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.entity.PrisonStaff
import uk.gov.justice.digital.hmpps.exception.NotFoundException
import uk.gov.justice.digital.hmpps.exceptions.InvalidEstablishmentCodeException
import uk.gov.justice.digital.hmpps.integrations.delius.entity.ProbationArea
import uk.gov.justice.digital.hmpps.integrations.delius.entity.Staff
import uk.gov.justice.digital.hmpps.integrations.delius.entity.Team
import uk.gov.justice.digital.hmpps.integrations.delius.model.StaffName
import uk.gov.justice.digital.hmpps.integrations.delius.repository.ProbationAreaRepository
import uk.gov.justice.digital.hmpps.integrations.delius.repository.TeamRepository
import uk.gov.justice.digital.hmpps.model.StaffName
import uk.gov.justice.digital.hmpps.repository.PrisonProbationAreaRepository
import uk.gov.justice.digital.hmpps.repository.PrisonTeamRepository
import uk.gov.justice.digital.hmpps.retry.retry
import java.time.ZonedDateTime

@Service
class AssignmentService(
private val probationAreaRepository: ProbationAreaRepository,
private val teamRepository: TeamRepository,
private val probationAreaRepository: PrisonProbationAreaRepository,
private val teamRepository: PrisonTeamRepository,
private val staffService: StaffService
) {

Expand All @@ -27,14 +26,20 @@ class AssignmentService(
)
val team = teamRepository.findByCode("${pa.code}CSN")
?: throw NotFoundException("Team", "code", "${pa.code}CSN")
val staff = getStaff(pa, team, staffName)
val staff = getStaff(pa.id, pa.code, team.id, staffName)
return Triple(pa.id, team.id, staff.id)
}

private fun getStaff(probationArea: ProbationArea, team: Team, staffName: StaffName): Staff {
val findStaff = { staffService.findStaff(probationArea.id, staffName) }
fun getStaff(
probationAreaId: Long,
probationAreaCode: String,
teamId: Long,
staffName: StaffName,
allocationDate: ZonedDateTime? = null
): PrisonStaff {
val findStaff = { staffService.findStaff(probationAreaId, staffName) }
return retry(3) {
findStaff() ?: staffService.create(probationArea, team, staffName)
findStaff() ?: staffService.create(probationAreaId, probationAreaCode, teamId, staffName, allocationDate)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package uk.gov.justice.digital.hmpps.integrations.delius.service
package uk.gov.justice.digital.hmpps.service

import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.exceptions.StaffCodeExhaustedException
import uk.gov.justice.digital.hmpps.integrations.delius.repository.StaffRepository
import uk.gov.justice.digital.hmpps.repository.PrisonStaffRepository

@Component
class OfficerCodeGenerator(private val staffRepository: StaffRepository) {
class OfficerCodeGenerator(private val staffRepository: PrisonStaffRepository) {
private val alphabet = ('A'..'Z').toList()

fun generateFor(probationAreaCode: String, index: Int = 0): String {
Expand Down
Loading

0 comments on commit cbb862c

Please sign in to comment.