diff --git a/projects/approved-premises-and-delius/deploy/values-dev.yml b/projects/approved-premises-and-delius/deploy/values-dev.yml index 53cff5cc76..a5dcfbb172 100644 --- a/projects/approved-premises-and-delius/deploy/values-dev.yml +++ b/projects/approved-premises-and-delius/deploy/values-dev.yml @@ -11,7 +11,7 @@ generic-service: SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/issuer INTEGRATIONS_APPROVED-PREMISES-API_URL: https://approved-premises-api-dev.hmpps.service.justice.gov.uk - + INTEGRATIONS_ALFRESCO_URL: https://alfresco.test.delius.probation.hmpps.dsd.io/alfresco/service/noms-spg/ LOGGING_LEVEL_UK_GOV_DIGITAL_JUSTICE_HMPPS: DEBUG generic-prometheus-alerts: diff --git a/projects/approved-premises-and-delius/deploy/values-preprod.yml b/projects/approved-premises-and-delius/deploy/values-preprod.yml index 89a57a22dd..dcbcb03828 100644 --- a/projects/approved-premises-and-delius/deploy/values-preprod.yml +++ b/projects/approved-premises-and-delius/deploy/values-preprod.yml @@ -11,6 +11,7 @@ generic-service: SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/issuer INTEGRATIONS_APPROVED-PREMISES-API_URL: https://approved-premises-api-preprod.hmpps.service.justice.gov.uk + INTEGRATIONS_ALFRESCO_URL: https://alfresco.pre-prod.delius.probation.hmpps.dsd.io/alfresco/service/noms-spg/ generic-prometheus-alerts: businessHoursOnly: true \ No newline at end of file diff --git a/projects/approved-premises-and-delius/deploy/values-prod.yml b/projects/approved-premises-and-delius/deploy/values-prod.yml index 04ae56a195..1c158c6810 100644 --- a/projects/approved-premises-and-delius/deploy/values-prod.yml +++ b/projects/approved-premises-and-delius/deploy/values-prod.yml @@ -8,3 +8,4 @@ generic-service: SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/issuer INTEGRATIONS_APPROVED-PREMISES-API_URL: https://approved-premises-api.hmpps.service.justice.gov.uk + INTEGRATIONS_ALFRESCO_URL: https://alfresco.probation.service.justice.gov.uk/alfresco/service/noms-spg/ \ No newline at end of file diff --git a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index fda87f796d..c6bc90c7be 100644 --- a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -16,6 +16,7 @@ import uk.gov.justice.digital.hmpps.data.generator.NsiStatusGenerator import uk.gov.justice.digital.hmpps.data.generator.NsiTypeGenerator import uk.gov.justice.digital.hmpps.data.generator.OfficeLocationGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.ANOTHER_EVENT import uk.gov.justice.digital.hmpps.data.generator.PersonManagerGenerator import uk.gov.justice.digital.hmpps.data.generator.ProbationAreaGenerator import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator @@ -188,6 +189,7 @@ class DataLoader( caseloadRepository.save(CaseloadGenerator.generate(person, TeamGenerator.APPROVED_PREMISES_TEAM)) caseloadRepository.save(CaseloadGenerator.generate(person, TeamGenerator.UNALLOCATED)) + eventRepository.save(ANOTHER_EVENT) referralRepository.save(ReferralGenerator.EXISTING_REFERRAL) probationCaseDataLoader.loadData() diff --git a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiTypeGenerator.kt b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiTypeGenerator.kt index 5814407fe2..cd902d2dc5 100644 --- a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiTypeGenerator.kt +++ b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/NsiTypeGenerator.kt @@ -4,7 +4,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention.entity.NsiType object NsiTypeGenerator { - fun generate(code: String, id: Long = IdGenerator.getAndIncrement()) = NsiType(id, code) + fun generate(code: String, id: Long = IdGenerator.getAndIncrement()) = NsiType(id, code, "description of $code") } object NsiStatusGenerator { diff --git a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt index 0da29c0517..169d087563 100644 --- a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt +++ b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -14,6 +14,7 @@ import java.time.ZonedDateTime object PersonGenerator { val DEFAULT = generate(crn = "A000001") val EVENT = generateEvent("7", DEFAULT.id) + val ANOTHER_EVENT = generateEvent("8", DEFAULT.id) fun generate( crn: String, id: Long = IdGenerator.getAndIncrement() diff --git a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferralGenerator.kt b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferralGenerator.kt index 92c6ced091..b29bdca61f 100644 --- a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferralGenerator.kt +++ b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ReferralGenerator.kt @@ -11,7 +11,7 @@ object ReferralGenerator { fun generateReferral( person: Person = PersonGenerator.DEFAULT, - eventId: Long = IdGenerator.getAndIncrement(), + eventId: Long = PersonGenerator.ANOTHER_EVENT.id, approvedPremises: ApprovedPremises = ApprovedPremisesGenerator.DEFAULT, referralDate: LocalDate = LocalDate.now(), expectedArrivalDate: LocalDate? = LocalDate.now().plusDays(1), diff --git a/projects/approved-premises-and-delius/src/dev/resources/simulations/__files/document.pdf b/projects/approved-premises-and-delius/src/dev/resources/simulations/__files/document.pdf new file mode 100644 index 0000000000..88d1cf8ed6 Binary files /dev/null and b/projects/approved-premises-and-delius/src/dev/resources/simulations/__files/document.pdf differ diff --git a/projects/approved-premises-and-delius/src/dev/resources/simulations/mappings/alfresco.json b/projects/approved-premises-and-delius/src/dev/resources/simulations/mappings/alfresco.json new file mode 100644 index 0000000000..130dc50589 --- /dev/null +++ b/projects/approved-premises-and-delius/src/dev/resources/simulations/mappings/alfresco.json @@ -0,0 +1,15 @@ +{ + "request": { + "method": "GET", + "urlPath": "/alfresco/fetch/uuid1" + }, + "response": { + "headers": { + "Content-Type": "application/octet-stream", + "Content-Disposition": "attachment; filename=\"doc1\"; filename*=UTF-8''doc1", + "Custom-Alfresco-Header": "should be ignored" + }, + "status": 200, + "bodyFileName": "document.pdf" + } +} \ No newline at end of file diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/FeignOAuth2Config.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/FeignOAuth2Config.kt index 8c3f4eee51..fa145438be 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/FeignOAuth2Config.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/FeignOAuth2Config.kt @@ -4,10 +4,11 @@ import org.springframework.cloud.openfeign.EnableFeignClients import org.springframework.context.annotation.Configuration import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager import uk.gov.justice.digital.hmpps.config.feign.FeignConfig +import uk.gov.justice.digital.hmpps.integrations.alfresco.AlfrescoClient import uk.gov.justice.digital.hmpps.integrations.approvedpremises.ApprovedPremisesApiClient @Configuration -@EnableFeignClients(clients = [ApprovedPremisesApiClient::class]) +@EnableFeignClients(clients = [ApprovedPremisesApiClient::class, AlfrescoClient::class]) class FeignOAuth2Config( authorizedClientManager: OAuth2AuthorizedClientManager ) : FeignConfig(authorizedClientManager) { diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/DocumentController.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/DocumentController.kt new file mode 100644 index 0000000000..d7b8a8c89d --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/DocumentController.kt @@ -0,0 +1,40 @@ +package uk.gov.justice.digital.hmpps.controller + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.APDocument +import uk.gov.justice.digital.hmpps.service.DocumentService + +@RestController +@Tag(name = "Documents") +@RequestMapping("/document/{crn}") +@PreAuthorize("hasRole('ROLE_APPROVED_PREMISES_STAFF')") +class DocumentController(private val documentService: DocumentService) { + + @GetMapping(value = ["/{id}"]) + @Operation(summary = "Download document content") + fun downloadDocument( + @PathVariable crn: String, + @PathVariable id: String + ) = documentService.downloadDocument(crn, id) + + @PreAuthorize("hasRole('ROLE_APPROVED_PREMISES_STAFF')") + @Operation( + summary = "List of documents held in Delius for the probation case", + description = """List of documents available in Delius for the probation + case identified by the CRN provided in the request. Document list + includes summary information on the type and purpose of document held. + Used to support the 'Document List' view of the HMPPS Workforce service + which is used to give detailed information on the case when allocating + to a probation practitioner + """ + ) + @GetMapping + fun findDocuments(@PathVariable crn: String): List = + documentService.getDocumentsByCrn(crn) +} diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/alfresco/AlfrescoClient.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/alfresco/AlfrescoClient.kt new file mode 100644 index 0000000000..592215f20a --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/alfresco/AlfrescoClient.kt @@ -0,0 +1,25 @@ +package uk.gov.justice.digital.hmpps.integrations.alfresco + +import feign.RequestInterceptor +import org.springframework.cloud.openfeign.FeignClient +import org.springframework.context.annotation.Bean +import org.springframework.core.io.Resource +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import uk.gov.justice.digital.hmpps.security.ServiceContext + +@FeignClient(name = "alfresco", url = "\${integrations.alfresco.url}", configuration = [AlfrescoFeignConfig::class]) +interface AlfrescoClient { + @GetMapping(value = ["/fetch/{id}"]) + fun getDocument(@PathVariable id: String): ResponseEntity +} + +class AlfrescoFeignConfig { + @Bean + fun requestInterceptor() = RequestInterceptor { template -> + template.header("X-DocRepository-Remote-User", "N00") + template.header("X-DocRepository-Real-Remote-User", ServiceContext.servicePrincipal()!!.username) + template.header("Content-Type: multipart/form-data") + } +} diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/approvedpremises/referral/entity/Referral.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/approvedpremises/referral/entity/Referral.kt index 081ba58441..18fbdae308 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/approvedpremises/referral/entity/Referral.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/approvedpremises/referral/entity/Referral.kt @@ -38,6 +38,7 @@ class Referral( @Column(name = "offender_id") val personId: Long, + @Column(name = "event_id") val eventId: Long, val approvedPremisesId: Long, diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact/Contact.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact/Contact.kt index 28529a1c7f..0cdd6edb65 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact/Contact.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact/Contact.kt @@ -56,6 +56,7 @@ class Contact( @JoinColumn(name = "offender_id", nullable = false) val person: Person, + @Column(name = "event_id") val eventId: Long? = null, @Lob diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/DocumentRepository.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/DocumentRepository.kt new file mode 100644 index 0000000000..54c295ae2f --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/DocumentRepository.kt @@ -0,0 +1,12 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.Document + +interface DocumentRepository : JpaRepository { + @Query("select d.name from Document d where d.person.crn = :crn and d.alfrescoId = :alfrescoId") + fun findNameByPersonCrnAndAlfrescoId(crn: String, alfrescoId: String): String? + + fun findAllByPersonIdAndSoftDeletedIsFalse(personId: Long): List +} diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/ApprovedPremisesReferral.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/ApprovedPremisesReferral.kt new file mode 100644 index 0000000000..d7563350cd --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/ApprovedPremisesReferral.kt @@ -0,0 +1,28 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.ReferenceData + +@Entity +@Immutable +@Table(name = "approved_premises_referral") +class ApprovedPremisesReferral( + @Id + @Column(name = "approved_premises_referral_id") + val id: Long, + + @JoinColumn(name = "event_id", insertable = false, updatable = false) + @ManyToOne + val event: DocEvent, + + @JoinColumn(name = "referral_category_id", insertable = false, updatable = false) + @ManyToOne + val category: ReferenceData + +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/CaseAllocationDoc.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/CaseAllocationDoc.kt new file mode 100644 index 0000000000..2a67d34554 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/CaseAllocationDoc.kt @@ -0,0 +1,22 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +@Table(name = "case_allocation") +class CaseAllocationDoc( + @Id + @Column(name = "case_allocation_id") + val id: Long, + + @JoinColumn(name = "event_id", insertable = false, updatable = false) + @ManyToOne + val event: DocEvent +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/CourtReportDoc.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/CourtReportDoc.kt new file mode 100644 index 0000000000..2452778774 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/CourtReportDoc.kt @@ -0,0 +1,51 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +@Table(name = "court_report") +class CourtReportDoc( + @Id + @Column(name = "court_report_id") + val id: Long, + + @JoinColumn(name = "court_appearance_id", insertable = false, updatable = false) + @ManyToOne + val documentCourtAppearance: DocumentCourtAppearance? = null, + + @ManyToOne + @JoinColumn(name = "court_report_type_id", updatable = false) + val type: CourtReportType +) + +@Immutable +@Entity +@Table(name = "r_court_report_type") +class CourtReportType( + @Id + @Column(name = "court_report_type_id") + val id: Long, + + val description: String +) + +@Entity +@Immutable +@Table(name = "court_appearance") +class DocumentCourtAppearance( + + @Id + @Column(name = "court_appearance_id") + val id: Long, + + @JoinColumn(name = "event_id", insertable = false, updatable = false) + @ManyToOne + val event: DocEvent +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocAddressAssessment.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocAddressAssessment.kt new file mode 100644 index 0000000000..7d0e8361ae --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocAddressAssessment.kt @@ -0,0 +1,33 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +class AddressAssessment( + @Id + @Column(name = "address_assessment_id") + var id: Long, + + @ManyToOne + @JoinColumn(name = "offender_address_id", insertable = false, updatable = false) + val personAddress: DocPersonAddress? +) + +@Entity +@Table(name = "offender_address") +@Immutable +class DocPersonAddress( + @Id + @Column(name = "offender_address_id") + var id: Long, + val buildingName: String?, + val addressNumber: String?, + val streetName: String? +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocContact.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocContact.kt new file mode 100644 index 0000000000..f518eded4f --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocContact.kt @@ -0,0 +1,37 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +@Table(name = "contact") +class DocContact( + @Id + @Column(name = "contact_id", updatable = false) + val id: Long = 0, + + @JoinColumn(name = "event_id", insertable = false, updatable = false) + @ManyToOne + val event: DocEvent?, + + @ManyToOne + @JoinColumn(name = "contact_type_id", updatable = false) + val type: DocContactType +) + +@Immutable +@Entity +@Table(name = "r_contact_type") +class DocContactType( + @Id + @Column(name = "contact_type_id") + val id: Long, + + val description: String +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocEvent.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocEvent.kt new file mode 100644 index 0000000000..d3789abdf3 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocEvent.kt @@ -0,0 +1,97 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.OneToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import uk.gov.justice.digital.hmpps.integrations.delius.person.Person + +@Immutable +@Entity +@Table(name = "event") +class DocEvent( + @Id + @Column(name = "event_id", nullable = false) + val id: Long, + + @ManyToOne + @JoinColumn(name = "offender_id", nullable = false) + val person: Person, + + @Column(name = "active_flag", columnDefinition = "NUMBER", nullable = false) + val active: Boolean, + + @Column(name = "event_number", nullable = false) + val eventNumber: String, + + @OneToOne(mappedBy = "event") + val disposal: DocDisposal? = null, + + @OneToOne(mappedBy = "event") + val mainOffence: DocMainOffence? = null +) + +@Immutable +@Entity +@Table(name = "disposal") +class DocDisposal( + @Id + @Column(name = "disposal_id") + val id: Long, + + @OneToOne + @JoinColumn(name = "event_id", updatable = false) + val event: DocEvent, + + @ManyToOne + @JoinColumn(name = "disposal_type_id", updatable = false) + val type: DocDisposalType, + + @Column(name = "active_flag", updatable = false, columnDefinition = "NUMBER") + val active: Boolean = true, + + @Column(updatable = false, columnDefinition = "NUMBER") + val softDeleted: Boolean = false +) + +@Immutable +@Entity +@Table(name = "r_disposal_type") +class DocDisposalType( + @Id + @Column(name = "disposal_type_id") + val id: Long, + val description: String +) + +@Immutable +@Entity +@Table(name = "r_offence") +class DocOffence( + @Id + @Column(name = "offence_id") + val id: Long, + + val description: String +) + +@Immutable +@Entity +@Table(name = "main_offence") +class DocMainOffence( + @Id + @Column(name = "main_offence_id") + val id: Long, + + @JoinColumn(name = "offence_id") + @OneToOne + val offence: DocOffence, + + @JoinColumn(name = "event_id") + @OneToOne + val event: DocEvent +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocNsi.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocNsi.kt new file mode 100644 index 0000000000..811af4cbf2 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocNsi.kt @@ -0,0 +1,28 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention.entity.NsiType + +@Entity +@Immutable +@Table(name = "nsi") +class DocNsi( + @Id + @Column(name = "nsi_id", updatable = false) + val id: Long = 0, + + @JoinColumn(name = "event_id", insertable = false, updatable = false) + @ManyToOne + val event: DocEvent?, + + @ManyToOne + @JoinColumn(name = "nsi_type_id", updatable = false) + val type: NsiType +) + diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocPerson.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocPerson.kt new file mode 100644 index 0000000000..90f6e6edd8 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocPerson.kt @@ -0,0 +1,28 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import org.springframework.data.jpa.repository.JpaRepository + +@Immutable +@Entity +@Table(name = "offender") +class DocPerson( + + @Id + @Column(name = "offender_id") + val id: Long, + + @Column(columnDefinition = "CHAR(7)") + val crn: String, + + @Column(updatable = false, columnDefinition = "NUMBER") + val softDeleted: Boolean = false +) + +interface DocPersonRepository : JpaRepository { + fun findByCrn(crn: String): DocPerson? +} \ No newline at end of file diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocPersonalContact.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocPersonalContact.kt new file mode 100644 index 0000000000..7ecf5a9ab7 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocPersonalContact.kt @@ -0,0 +1,29 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.ReferenceData + +@Entity +@Immutable +@Table(name = "personal_contact") +class DocPersonalContact( + @Id + @Column(name = "personal_contact_id") + var id: Long, + + @Column(name = "first_name") + val forename: String, + + @Column(name = "surname") + val surname: String, + + @ManyToOne + @JoinColumn(name = "title_id", insertable = false, updatable = false) + val title: ReferenceData? +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocReferral.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocReferral.kt new file mode 100644 index 0000000000..afd2f9d3e1 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocReferral.kt @@ -0,0 +1,63 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +@Table(name = "referral") +class DocReferral( + @Id + @Column(name = "referral_id") + val id: Long, + + @JoinColumn(name = "event_id", insertable = false, updatable = false) + @ManyToOne + val event: DocEvent, + + @JoinColumn(name = "REFERRAL_TYPE_ID") + @ManyToOne + val type: ReferralType +) + +@Entity +@Immutable +@Table(name = "assessment") +class DocAssessment( + @Id + @Column(name = "assessment_id") + val id: Long, + + @JoinColumn(name = "referral_id", insertable = false, updatable = false) + @ManyToOne + val docReferral: DocReferral? = null, + + @JoinColumn(name = "ASSESSMENT_TYPE_ID") + @ManyToOne + val type: AssessmentType +) + +@Entity +@Immutable +@Table(name = "r_assessment_type") +class AssessmentType( + @Id + @Column(name = "assessment_type_id") + val id: Long, + val description: String +) + +@Entity +@Immutable +@Table(name = "r_referral_type") +class ReferralType( + @Id + @Column(name = "referral_type_id") + val id: Long, + val description: String +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocRegistration.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocRegistration.kt new file mode 100644 index 0000000000..9a899175c6 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/DocRegistration.kt @@ -0,0 +1,34 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +@Table(name = "Registration") +class DocRegistration( + @Id + @Column(name = "registration_id") + var id: Long, + + @ManyToOne + @JoinColumn(name = "register_type_id", updatable = false) + val type: DocRegistrationType +) + +@Entity +@Table(name = "r_register_type") +@Immutable +class DocRegistrationType( + @Id + @Column(name = "REGISTER_TYPE_ID") + var id: Long, + + @Column + val description: String +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/Document.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/Document.kt new file mode 100644 index 0000000000..bc0db27497 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/Document.kt @@ -0,0 +1,423 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Convert +import jakarta.persistence.DiscriminatorColumn +import jakarta.persistence.DiscriminatorType +import jakarta.persistence.DiscriminatorValue +import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import jakarta.persistence.Id +import jakarta.persistence.Inheritance +import jakarta.persistence.InheritanceType +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.NotFound +import org.hibernate.annotations.NotFoundAction +import org.hibernate.type.YesNoConverter +import uk.gov.justice.digital.hmpps.integrations.delius.person.Person +import java.time.ZonedDateTime + +@Entity +@Immutable +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "table_name", discriminatorType = DiscriminatorType.STRING) +abstract class Document : Relatable { + @Id + @Column(name = "document_id") + open var id: Long = 0 + + @Column(name = "document_name") + open var name: String = "" + + @ManyToOne + @JoinColumn(name = "offender_id") + open val person: Person? = null + + @Column(name = "primary_key_id") + open var primaryKeyId: Long = 0 + + @Column(columnDefinition = "char(1)") + open var status: String = "N" + open var softDeleted: Boolean = false + + @Convert(converter = YesNoConverter::class) + open var workInProgress: Boolean? = false + + @Column(name = "alfresco_document_id") + open var alfrescoId: String? = null + open var sensitive: Boolean = false + open var lastSaved: ZonedDateTime? = ZonedDateTime.now() + open var dateProduced: ZonedDateTime? = ZonedDateTime.now() + + @Column(name = "created_datetime") + open var createdDate: ZonedDateTime? = ZonedDateTime.now() + + @Column(name = "document_type") + @Enumerated(EnumType.STRING) + open var type: DocumentType = DocumentType.DOCUMENT +} + +enum class DocumentType { + DOCUMENT, + CPS_PACK, + PREVIOUS_CONVICTION +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("EQUALITY") +class Equality : Document() { + override fun findRelatedTo(): RelatedTo = RelatedTo(RelatedType.EQUALITY) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("DRUGS_TEST") +class DrugTest : Document() { + override fun findRelatedTo(): RelatedTo = RelatedTo(RelatedType.DRUGS_TEST) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("OFFENDER") +class OffenderDocument : Document() { + override fun findRelatedTo(): RelatedTo = + if (type == DocumentType.PREVIOUS_CONVICTION) { + RelatedTo(RelatedType.PRECONS) + } else { + RelatedTo(RelatedType.PERSON) + } +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("OFFENDER_ADDRESS") +class OffenderAddress : Document() { + override fun findRelatedTo(): RelatedTo = RelatedTo(RelatedType.OFFENDER_ADDRESS) +} + +const val entityNotFound = "ENTITY_NOT_FOUND" + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("EVENT") +class EventDocument( + @JoinColumn(name = "primary_key_id", referencedColumnName = "event_id", insertable = false, updatable = false) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val event: DocEvent? +) : Document() { + override fun findRelatedTo(): RelatedTo = + if (type == DocumentType.CPS_PACK) { + RelatedTo( + RelatedType.CPSPACK, + event = event?.toDocumentEvent() + ) + } else { + RelatedTo( + RelatedType.EVENT, + if (event == null) entityNotFound else event.disposal?.type?.description ?: "", + event?.toDocumentEvent() + ) + } +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("ADDRESSASSESSMENT") +class AddressAssessmentDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "address_assessment_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val addressAssessment: AddressAssessment? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.ADDRESS_ASSESSMENT, + getPersonAddressLine(addressAssessment?.personAddress) + ) + + private fun getPersonAddressLine(personAddress: DocPersonAddress?): String { + if (personAddress == null) { + return entityNotFound + } else { + ( + return listOfNotNull( + personAddress.buildingName, + personAddress.addressNumber, + personAddress.streetName + ).joinToString(", ") + ) + } + } +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("APPROVED_PREMISES_REFERRAL") +class ApprovedPremisesReferralDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "approved_premises_referral_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val approvedPremisesReferral: ApprovedPremisesReferral? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.APPROVED_PREMISES_REFERRAL, + approvedPremisesReferral?.category?.description ?: entityNotFound, + approvedPremisesReferral?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("ASSESSMENT") +class AssessmentDocument( + @JoinColumn(name = "primary_key_id", referencedColumnName = "assessment_id", insertable = false, updatable = false) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val docAssessment: DocAssessment? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.ASSESSMENT, + docAssessment?.type?.description ?: entityNotFound, + docAssessment?.docReferral?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("CASE_ALLOCATION") +class CaseAllocationDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "case_allocation_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val allocation: CaseAllocationDoc? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.CASE_ALLOCATION, + allocation?.event?.disposal?.type?.description ?: entityNotFound, + allocation?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("CONTACT") +class ContactDocument( + @JoinColumn(name = "primary_key_id", referencedColumnName = "contact_id", insertable = false, updatable = false) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val contact: DocContact? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.CONTACT, + contact?.type?.description ?: entityNotFound, + contact?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("COURT_REPORT") +class CourtReportDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "court_report_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val courtReportDoc: CourtReportDoc? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.COURT_REPORT, + courtReportDoc?.type?.description ?: entityNotFound, + courtReportDoc?.documentCourtAppearance?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("INSTITUTIONAL_REPORT") +class InstitutionalReportDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "institutional_report_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val institutionalReport: InstitutionalReport? +) : Document() { + + override fun findRelatedTo(): RelatedTo = + RelatedTo(RelatedType.INSTITUTIONAL_REPORT, institutionalReport?.type?.description ?: entityNotFound) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("NSI") +class NsiDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "nsi_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val docNsi: DocNsi? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.NSI, + docNsi?.type?.description ?: entityNotFound, + docNsi?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("PERSONAL_CIRCUMSTANCE") +class PersonalCircumstanceDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "personal_circumstance_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val personalCircumstance: PersonalCircumstance? +) : Document() { + + override fun findRelatedTo(): RelatedTo = + RelatedTo(RelatedType.PERSONAL_CIRCUMSTANCE, getCircName()) + + private fun getCircName(): String { + var circName: String = personalCircumstance?.type?.description ?: entityNotFound + if (personalCircumstance?.subType != null) { + circName += " - ${personalCircumstance.subType.description}" + } + return circName + } +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("PERSONALCONTACT") +class PersonalContactDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "personal_contact_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val personalContact: DocPersonalContact? +) : Document() { + + override fun findRelatedTo(): RelatedTo = + RelatedTo(RelatedType.PERSONAL_CONTACT, getPersonalContactLine()) + + private fun getPersonalContactLine(): String { + return if (personalContact == null) { + entityNotFound + } else { + listOfNotNull( + personalContact.title?.description, + personalContact.forename, + personalContact.surname + ).joinToString(" ") + } + } +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("REFERRAL") +class ReferralDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "referral_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val docReferral: DocReferral? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.REFERRAL, + docReferral?.type?.description ?: entityNotFound, + docReferral?.event?.toDocumentEvent() + ) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("REGISTRATION") +class RegistrationDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "registration_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val registration: DocRegistration? +) : Document() { + + override fun findRelatedTo(): RelatedTo = + RelatedTo(RelatedType.REGISTRATION, registration?.type?.description ?: entityNotFound) +} + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorValue("UPW_APPOINTMENT") +class UPWAppointmentDocument( + @JoinColumn( + name = "primary_key_id", + referencedColumnName = "upw_appointment_id", + insertable = false, + updatable = false + ) + @ManyToOne + @NotFound(action = NotFoundAction.IGNORE) + val upwAppointment: UpwAppointment? +) : Document() { + override fun findRelatedTo(): RelatedTo = + RelatedTo( + RelatedType.UPW_APPOINTMENT, + upwAppointment?.upwDetails?.disposal?.type?.description ?: entityNotFound, + upwAppointment?.upwDetails?.disposal?.event?.toDocumentEvent() + ) +} diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/InstitutionalReport.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/InstitutionalReport.kt new file mode 100644 index 0000000000..4e1c24978b --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/InstitutionalReport.kt @@ -0,0 +1,34 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import org.hibernate.annotations.Immutable +import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.ReferenceData +import java.time.LocalDate + +@Entity +@Immutable +class InstitutionalReport( + @Id + @Column(name = "institutional_report_id") + val id: Long, + + @ManyToOne + @JoinColumn(name = "institution_report_type_id", updatable = false) + val type: ReferenceData, + + @Column(name = "date_required") + val dateRequired: LocalDate, + + @Column(name = "date_completed") + val dateCompleted: LocalDate? = null, + + @Column(updatable = false, columnDefinition = "NUMBER") + val softDeleted: Boolean = false, + + @Column(name = "custody_id") + val custodyId: Long +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/PersonDocument.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/PersonDocument.kt new file mode 100644 index 0000000000..e1bdf0370d --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/PersonDocument.kt @@ -0,0 +1,67 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import java.time.ZonedDateTime + +data class PersonDocument( + val id: String?, + val name: String, + val relatedTo: RelatedTo, + val dateSaved: ZonedDateTime?, + val dateCreated: ZonedDateTime?, + val sensitive: Boolean +) + +data class APDocument( + val id: String?, + val level: String, + val filename: String, + val typeCode: String, + val typeDescription: String, + val dateSaved: ZonedDateTime?, + val dateCreated: ZonedDateTime?, + val description: String? +) + +data class RelatedTo( + val type: RelatedType, + val name: String = "", + val event: DocumentEvent? = null +) { + val description: String = type.description() +} + +data class DocumentEvent( + val eventType: EventType, + val eventNumber: String, + val mainOffence: String +) + +enum class EventType { + CURRENT, PREVIOUS +} + +enum class RelatedType(private val displayName: String = "") { + ADDRESS_ASSESSMENT, + APPROVED_PREMISES_REFERRAL, + ASSESSMENT, + CASE_ALLOCATION, + CONTACT, + COURT_REPORT, + CPSPACK("Crown Prosecution Service case pack"), + DRUGS_TEST("Drug Test"), + PRECONS("PNC previous convictions"), + EVENT, + EQUALITY("Equality Monitoring"), + INSTITUTIONAL_REPORT, + NSI("Non Statutory Intervention"), + PERSON, + OFFENDER_ADDRESS, + PERSONAL_CONTACT, + PERSONAL_CIRCUMSTANCE, + REFERRAL, + REGISTRATION, + UPW_APPOINTMENT("Unpaid Work Appointment"); + + fun description(): String = + displayName.ifEmpty { name.split("_").joinToString(" ") { it.lowercase().replaceFirstChar(Char::titlecase) } } +} diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/PersonalCircumstance.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/PersonalCircumstance.kt new file mode 100644 index 0000000000..7cd1614e2d --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/PersonalCircumstance.kt @@ -0,0 +1,49 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +class PersonalCircumstance( + @Id + @Column(name = "personal_circumstance_id") + var id: Long, + + @ManyToOne + @JoinColumn(name = "circumstance_type_id", updatable = false) + val type: PersonalCircumstanceType, + + @ManyToOne + @JoinColumn(name = "circumstance_sub_type_id", updatable = false) + val subType: PersonalCircumstanceSubType? +) + +@Entity +@Table(name = "r_circumstance_type") +@Immutable +class PersonalCircumstanceType( + @Id + @Column(name = "circumstance_type_id") + var id: Long, + + @Column(name = "code_description") + val description: String +) + +@Entity +@Table(name = "r_circumstance_sub_type") +@Immutable +class PersonalCircumstanceSubType( + @Id + @Column(name = "circumstance_sub_type_id") + var id: Long, + + @Column(name = "code_description") + val description: String +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/Relatable.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/Relatable.kt new file mode 100644 index 0000000000..0993dd1033 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/Relatable.kt @@ -0,0 +1,11 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +interface Relatable { + fun findRelatedTo(): RelatedTo +} + +fun DocEvent.toDocumentEvent() = DocumentEvent( + if (active) EventType.CURRENT else EventType.PREVIOUS, + eventNumber, + mainOffence?.offence?.description ?: "" +) diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/UpwAppointment.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/UpwAppointment.kt new file mode 100644 index 0000000000..936ff33a87 --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/document/entity/UpwAppointment.kt @@ -0,0 +1,34 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.document.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +class UpwAppointment { + + @Id + @Column(name = "upw_appointment_id", insertable = false, updatable = false) + val id: Long = 0 + + @JoinColumn(name = "upw_details_id", insertable = false, updatable = false) + @ManyToOne + val upwDetails: UpwDetails? = null +} + +@Entity +@Immutable +class UpwDetails { + + @Id + @Column(name = "upw_details_id", updatable = false) + val id: Long = 0 + + @JoinColumn(name = "DISPOSAL_ID") + @ManyToOne + val disposal: DocDisposal? = null +} diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/nonstatutoryintervention/entity/NsiType.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/nonstatutoryintervention/entity/NsiType.kt index 5c22fa118e..9009534e88 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/nonstatutoryintervention/entity/NsiType.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/nonstatutoryintervention/entity/NsiType.kt @@ -17,7 +17,9 @@ class NsiType( val id: Long = 0, @Column(name = "code") - val code: String + val code: String, + + val description: String ) enum class NsiTypeCode(val code: String) { diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/DocumentService.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/DocumentService.kt new file mode 100644 index 0000000000..861e08ec2e --- /dev/null +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/DocumentService.kt @@ -0,0 +1,74 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.core.io.Resource +import org.springframework.http.ContentDisposition +import org.springframework.http.HttpHeaders.CONTENT_DISPOSITION +import org.springframework.http.HttpHeaders.CONTENT_LENGTH +import org.springframework.http.HttpHeaders.CONTENT_TYPE +import org.springframework.http.HttpHeaders.ETAG +import org.springframework.http.HttpHeaders.LAST_MODIFIED +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.integrations.alfresco.AlfrescoClient +import uk.gov.justice.digital.hmpps.integrations.delius.document.DocumentRepository +import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.APDocument +import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.DocPersonRepository +import kotlin.text.Charsets.UTF_8 + +@Service +class DocumentService( + private val documentRepository: DocumentRepository, + private val docPersonRepository: DocPersonRepository, + private val alfrescoClient: AlfrescoClient +) { + fun downloadDocument(crn: String, id: String): ResponseEntity { + val filename = documentRepository.findNameByPersonCrnAndAlfrescoId(crn, id) + ?: throw NotFoundException("Document with id of $id not found for CRN $crn") + + val response = alfrescoClient.getDocument(id) + + return when { + response.statusCode.is2xxSuccessful -> ResponseEntity.ok() + .headers { it.putAll(response.sanitisedHeaders()) } + .header( + CONTENT_DISPOSITION, + ContentDisposition.attachment().filename(filename, UTF_8).build().toString() + ) + .body(response.body) + + response.statusCode.is4xxClientError -> throw NotFoundException("Document content with id of $id not found for CRN $crn") + + else -> throw RuntimeException("Failed to download document. Alfresco responded with ${response.statusCode}.") + } + } + + fun getDocumentsByCrn(crn: String): List { + val person = docPersonRepository.findByCrn(crn) ?: throw NotFoundException("Person", "crn", crn) + val documents = ArrayList() + documents += documentRepository.findAllByPersonIdAndSoftDeletedIsFalse(person.id) + .map { + APDocument( + it.alfrescoId, + if (it.findRelatedTo().event == null) "Offender" else "Conviction", + it.name, + it.findRelatedTo().name, + it.findRelatedTo().description, + it.createdDate, + it.lastSaved, + it.type.name + ) + } + + return documents + } + + private fun ResponseEntity.sanitisedHeaders() = headers.filterKeys { + it in listOf( + CONTENT_LENGTH, + CONTENT_TYPE, + ETAG, + LAST_MODIFIED + ) + } +} diff --git a/projects/approved-premises-and-delius/src/main/resources/application.yml b/projects/approved-premises-and-delius/src/main/resources/application.yml index 5c49390028..abab51b077 100644 --- a/projects/approved-premises-and-delius/src/main/resources/application.yml +++ b/projects/approved-premises-and-delius/src/main/resources/application.yml @@ -39,6 +39,8 @@ springdoc.default-produces-media-type: application/json delius.db.username: ApprovedPremisesAndDelius # Should match value in [deploy/database/access.yml]. +integrations.alfresco.url: http://localhost:${wiremock.port}/alfresco + management.endpoints.web: base-path: / exposure.include: [ "health", "info" ] diff --git a/projects/approved-premises-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ApprovedPremisesServiceTest.kt b/projects/approved-premises-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ApprovedPremisesServiceTest.kt index 916ec2d96a..920cb74c39 100644 --- a/projects/approved-premises-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ApprovedPremisesServiceTest.kt +++ b/projects/approved-premises-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ApprovedPremisesServiceTest.kt @@ -558,7 +558,7 @@ internal class ApprovedPremisesServiceTest { whenever(transferReasonRepository.findByCode("NSI")) .thenReturn(TransferReason(IdGenerator.getAndIncrement(), "NSI")) types.forEach { - whenever(nsiTypeRepository.findByCode(it.code)).thenReturn(NsiType(IdGenerator.getAndIncrement(), it.code)) + whenever(nsiTypeRepository.findByCode(it.code)).thenReturn(NsiType(IdGenerator.getAndIncrement(), it.code, "description of ${it.code}")) } statuses.forEach { whenever(nsiStatusRepository.findByCode(it.code))