Skip to content

Commit

Permalink
DT-987 Calc Recall status on /offenders endpoint (#661)
Browse files Browse the repository at this point in the history
Co-authored-by: lbennett-moj <34441186+lbennett-moj@users.noreply.github.com>
  • Loading branch information
Mjwillis and lbennett-moj authored Jul 20, 2020
1 parent 664c714 commit b9c709f
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ public class InmateDetail {
@ApiModelProperty(value = "Offence History", notes = "Only returned when requesting extra details")
private List<OffenceHistoryDetail> offenceHistory;

@ApiModelProperty(value = "Current Sentence Terms", notes = "Only returned when requesting extra details")
private List<OffenderSentenceTerms> sentenceTerms;

@ApiModelProperty(value = "Aliases", notes = "Only returned when requesting extra details")
private List<Alias> aliases;

Expand All @@ -162,6 +165,9 @@ public class InmateDetail {
@ApiModelProperty(value = "Legal Status", example = "REMAND", notes = "Only returned when requesting extra details")
private LegalStatus legalStatus;

@ApiModelProperty(value = "Recall", example = "true", notes = "Only returned when requesting extra details")
private Boolean recall;

@ApiModelProperty(value = "The prisoner's imprisonment status.", example="LIFE", notes = "Only returned when requesting extra details")
private String imprisonmentStatus;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import java.util.List;

import static uk.gov.justice.hmpps.prison.api.model.LegalStatusCalc.LegalStatus.RECALL;

public class LegalStatusCalc {

@Getter
Expand All @@ -27,7 +29,38 @@ public enum LegalStatus {
}
}

private final static List<String> RECALL_STATUS_CODES = List.of("14FTR_ORA","14FTRHDC_ORA","CUR_ORA","FTR/08","FTR_HDC","FTR_HDC_ORA","FTR_ORA","FTR_SCH15","FTRSCH15_ORA","HDR_ORA","LR","LR_ALP","LR_ALP_LASPO","LR_DLP","LR_DPP","LR_EPP","LR_ES","LR_HDC","LR_IPP","LR_LASPO_AR","LR_LASPO_DR","LR_LIFE","LR_MLP","LR_ORA","LR_SEC236A","LR_SEC91_ORA","LR_YOI","LR_YOI_ORA");
private final static List<String> RECALL_STATUS_CODES = List.of("14FTR_ORA","14FTRHDC_ORA","CUR_ORA","FTR/08","FTR_HDC","FTR_HDC_ORA","FTR_ORA","FTR_SCH15","FTRSCH15_ORA","HDR_ORA","LR","LR_ALP","LR_ALP_LASPO","LR_DLP","LR_DPP","LR_EPP","LR_ES","LR_HDC","LR_IPP","LR_LASPO_AR","LR_LASPO_DR","LR_LIFE","LR_MLP","LR_ORA","LR_SEC236A","LR_SEC91_ORA","LR_YOI","LR_YOI_ORA");

public static final List<String> RECALL_SENTENCE_CODES = List.of("14FTRHDC_ORA",
"14FTR_ORA",
"CUR_ORA",
"FTR_HDC",
"FTR_HDC_ORA",
"FTR_ORA",
"FTR_SCH15",
"FTRSCH15_ORA",
"LR",
"LR_ALP",
"LR_ALP_LASPO",
"LR_DLP",
"LR_DPP",
"LR_EPP",
"LR_ES",
"LR_IPP",
"LR_LASPO_AR",
"LR_LASPO_DR",
"LR_LIFE",
"LR_MLP",
"LR_ORA",
"LR_SEC236A",
"LR_SEC91_ORA",
"LR_YOI_ORA",
"HDR_ORA",
"AGG_LR_ORA",
"AGG_HDR_ORA",
"AGGFTRHDCORA",
"FTR",
"HDR");

public static LegalStatus getLegalStatus(final String bandCode, final String mainLegalStatusCode) {

Expand Down Expand Up @@ -83,4 +116,19 @@ public static String getConvictedStatus(final String bandCode) {
}
return null;
}

public static boolean calcRecall(final Long bookingId, final LegalStatus legalStatus, final List<OffenceHistoryDetail> offenceHistory, final List<OffenderSentenceTerms> sentenceTerms) {
if (legalStatus == RECALL) {
return true;
} else {
if (offenceHistory.stream()
.filter(off -> off.getBookingId().equals(bookingId))
.anyMatch(off -> "1501".equals(off.getPrimaryResultCode()))) {
return true;
} else {
return sentenceTerms.stream()
.anyMatch(st -> RECALL_SENTENCE_CODES.contains(st.getSentenceType()));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public interface SentenceRepository {

List<OffenceHistoryDetail> getOffenceHistory(String offenderNo, boolean convictionsOnly);

List<OffenceHistoryDetail> getOffencesForBooking(Long bookingId, boolean convictionsOnly);

Optional<LocalDate> getConfirmedReleaseDate(Long bookingId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ public List<OffenceHistoryDetail> getOffenceHistory(final String offenderNo, fin
offenceHistoryMapper);
}

@Override
public List<OffenceHistoryDetail> getOffencesForBooking(final Long bookingId, final boolean convictionsOnly) {
Objects.requireNonNull(bookingId, "offenderNo is a required parameter");
final var sql = getQuery("GET_OFFENCES_FOR_BOOKING");

return jdbcTemplate.query(
sql,
createParams("bookingId", bookingId, "convictionsOnly", convictionsOnly ? "Y": "N"),
offenceHistoryMapper);
}

@Override
public Optional<LocalDate> getConfirmedReleaseDate(final Long bookingId) {
Objects.requireNonNull(bookingId, "bookingId is a required parameter");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -85,7 +84,6 @@

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.time.LocalDate.from;
import static java.time.LocalDate.now;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.util.Comparator.naturalOrder;
Expand Down Expand Up @@ -670,6 +668,10 @@ public List<OffenceHistoryDetail> getOffenceHistory(final String offenderNo, fin
return sentenceRepository.getOffenceHistory(offenderNo, convictionsOnly);
}

public List<OffenceHistoryDetail> getOffencesForBooking(final Long bookingId, final boolean convictionsOnly) {
return sentenceRepository.getOffencesForBooking(bookingId, convictionsOnly);
}

@VerifyBookingAccess(overrideRoles = {"SYSTEM_USER", "GLOBAL_SEARCH"})
public List<ScheduledEvent> getEventsToday(final Long bookingId) {
final var today = now();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.WordUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
Expand All @@ -26,6 +25,7 @@
import uk.gov.justice.hmpps.prison.api.model.ImageDetail;
import uk.gov.justice.hmpps.prison.api.model.InmateBasicDetails;
import uk.gov.justice.hmpps.prison.api.model.InmateDetail;
import uk.gov.justice.hmpps.prison.api.model.LegalStatusCalc;
import uk.gov.justice.hmpps.prison.api.model.OffenderBooking;
import uk.gov.justice.hmpps.prison.api.model.OffenderCategorise;
import uk.gov.justice.hmpps.prison.api.model.OffenderIdentifier;
Expand All @@ -43,8 +43,6 @@
import uk.gov.justice.hmpps.prison.api.support.Page;
import uk.gov.justice.hmpps.prison.api.support.PageRequest;
import uk.gov.justice.hmpps.prison.repository.InmateRepository;
import uk.gov.justice.hmpps.prison.repository.KeyWorkerAllocationRepository;
import uk.gov.justice.hmpps.prison.repository.UserRepository;
import uk.gov.justice.hmpps.prison.repository.jpa.model.OffenderLanguage;
import uk.gov.justice.hmpps.prison.repository.jpa.repository.OffenderLanguageRepository;
import uk.gov.justice.hmpps.prison.security.AuthenticationFacade;
Expand Down Expand Up @@ -94,10 +92,7 @@ public class InmateService {
private final ReferenceDomainService referenceDomainService;
private final AuthenticationFacade authenticationFacade;
private final int maxBatchSize;
private final UserRepository userRepository;
private final KeyWorkerAllocationRepository keyWorkerAllocationRepository;
private final OffenderLanguageRepository offenderLanguageRepository;
private final Environment env;
private final TelemetryClient telemetryClient;

private final String locationTypeGranularity;
Expand All @@ -109,10 +104,7 @@ public InmateService(final InmateRepository repository,
final BookingService bookingService,
final AgencyService agencyService,
final UserService userService,
final UserRepository userRepository,
final AuthenticationFacade authenticationFacade,
final KeyWorkerAllocationRepository keyWorkerAllocationRepository,
final Environment env,
final TelemetryClient telemetryClient,
@Value("${api.users.me.locations.locationType:WING}") final String locationTypeGranularity,
@Value("${batch.max.size:1000}") final int maxBatchSize,
Expand All @@ -125,9 +117,6 @@ public InmateService(final InmateRepository repository,
this.locationTypeGranularity = locationTypeGranularity;
this.bookingService = bookingService;
this.agencyService = agencyService;
this.userRepository = userRepository;
this.keyWorkerAllocationRepository = keyWorkerAllocationRepository;
this.env = env;
this.authenticationFacade = authenticationFacade;
this.maxBatchSize = maxBatchSize;
this.userService = userService;
Expand Down Expand Up @@ -240,9 +229,7 @@ private InmateDetail getOffenderDetails(final InmateDetail inmate, final boolean
inmate.setInterpreterRequired("Y".equalsIgnoreCase(offenderLanguage.getInterpreterRequestedFlag()));
});

getFirstPreferredWrittenLanguage(bookingId).ifPresent(offenderLanguage -> {
inmate.setWrittenLanguage(offenderLanguage.getReferenceCode().getDescription());
});
getFirstPreferredWrittenLanguage(bookingId).ifPresent(offenderLanguage -> inmate.setWrittenLanguage(offenderLanguage.getReferenceCode().getDescription()));

inmate.setPhysicalAttributes(getPhysicalAttributes(bookingId));
inmate.setPhysicalCharacteristics(getPhysicalCharacteristics(bookingId));
Expand All @@ -260,7 +247,6 @@ private InmateDetail getOffenderDetails(final InmateDetail inmate, final boolean
// TODO: Hack for now to make sure there wasn't a reason this was removed.
}
if (extraInfo) {
inmate.setOffenceHistory(bookingService.getOffenceHistory(inmate.getOffenderNo(), true));
inmate.setAliases(repository.findInmateAliases(bookingId, "createDate", Order.ASC, 0, 100).getItems());
inmate.setPrivilegeSummary(bookingService.getBookingIEPSummary(bookingId, false));
inmate.setIdentifiers(getOffenderIdentifiers(bookingId, null));
Expand All @@ -271,11 +257,19 @@ private InmateDetail getOffenderDetails(final InmateDetail inmate, final boolean
inmate.setLegalStatus(status.getLegalStatus());
inmate.setImprisonmentStatus(status.getImprisonmentStatus());
});

final var offenceHistory = bookingService.getOffencesForBooking(bookingId, true);
final var sentenceTerms = bookingService.getOffenderSentenceTerms(bookingId, null);
inmate.setOffenceHistory(offenceHistory);
inmate.setSentenceTerms(sentenceTerms);
inmate.setRecall(LegalStatusCalc.calcRecall(bookingId, inmate.getLegalStatus(), offenceHistory, sentenceTerms));
}
}
return inmate;
}



private Optional<OffenderLanguage> getFirstPreferredSpokenLanguage(final Long bookingId) {
return offenderLanguageRepository
.findByOffenderBookId(bookingId)
Expand Down
33 changes: 33 additions & 0 deletions src/main/resources/sqls/SentenceRepositoryImpl.sql
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,39 @@ WHERE OFFENDERS.OFFENDER_ID_DISPLAY = :offenderNo
ORDER BY OCH.offence_date
}

GET_OFFENCES_FOR_BOOKING {
SELECT OCH.OFFENDER_BOOK_ID AS BOOKING_ID,
OCH.OFFENCE_DATE,
OCH.OFFENCE_RANGE_DATE,
OFFS.DESCRIPTION AS OFFENCE_DESCRIPTION,
OCH.MOST_SERIOUS_FLAG AS MOST_SERIOUS,
OCH.OFFENCE_CODE,
OCH.STATUTE_CODE,
ORC1.CONVICTION_FLAG AS PRIMARY_RESULT_CONVICTION,
ORC2.CONVICTION_FLAG AS SECONDARY_RESULT_CONVICTION,
ORC1.DESCRIPTION AS PRIMARY_RESULT_DESCRIPTION,
ORC2.DESCRIPTION AS SECONDARY_RESULT_DESCRIPTION,
OCH.RESULT_CODE_1 AS PRIMARY_RESULT_CODE,
OCH.RESULT_CODE_2 AS SECONDARY_RESULT_CODE,
CEC.EVENT_DATE AS COURT_DATE,
OCH.CASE_ID
FROM OFFENDER_CHARGES OCH
INNER JOIN OFFENCES OFFS ON OFFS.OFFENCE_CODE = OCH.OFFENCE_CODE AND OFFS.STATUTE_CODE = OCH.STATUTE_CODE
LEFT JOIN OFFENCE_RESULT_CODES ORC1 ON OCH.RESULT_CODE_1 = ORC1.RESULT_CODE
LEFT JOIN OFFENCE_RESULT_CODES ORC2 ON OCH.RESULT_CODE_2 = ORC2.RESULT_CODE
LEFT JOIN ( SELECT max(EVENT_DATE) as event_date, OFFENDER_CHARGE_ID
from COURT_EVENT_CHARGES CEC inner join COURT_EVENTS CE on CEC.EVENT_ID = CE.EVENT_ID
group by CEC.OFFENDER_CHARGE_ID ) CEC on OCH.OFFENDER_CHARGE_ID = CEC.OFFENDER_CHARGE_ID
WHERE OCH.OFFENDER_BOOK_ID = :bookingId
AND ( :convictionsOnly = 'N' OR (
ORC1.CONVICTION_FLAG = 'Y'
OR ORC2.CONVICTION_FLAG = 'Y'
))
-- Avoid dups from merges (from NART team)
AND NOT (OCH.CREATE_USER_ID = 'SYS' AND OCH.AUDIT_MODULE_NAME = 'MERGE')
ORDER BY OCH.offence_date
}

GET_BOOKING_CONFIRMED_RELEASE_DATE {
SELECT RELEASE_DATE
FROM OFFENDER_RELEASE_DETAILS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ public class InmateServiceImplTest {
@BeforeEach
public void init() {
serviceToTest = new InmateService(repository, caseLoadService, inmateAlertService,
referenceDomainService, bookingService, agencyService, userService, userRepository, authenticationFacade,
keyWorkerAllocationRepository, env, telemetryClient, "WING", 100, offenderLanguageRepository);
referenceDomainService, bookingService, agencyService, userService, authenticationFacade, telemetryClient, "WING", 100, offenderLanguageRepository);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"offenderNo": "A1234AB",
"bookingId": -2,
"bookingNo": "A00112",
"offenderId": -1002,
"rootOffenderId": -1002,
"offenderNo": "A1234AB",
"firstName": "GILLIAN",
"middleName": "EVE",
"lastName": "ANDERSON",
"dateOfBirth": "1998-08-28",
"agencyId": "LEI",
"assignedLivingUnitId": -19,
"activeFlag": true,
Expand Down Expand Up @@ -48,9 +49,6 @@
"description": "H-1-5",
"agencyName": "Leeds"
},
"facialImageId": -2,
"dateOfBirth": "1998-08-28",
"age": 21,
"physicalAttributes": {
"gender": "Female",
"raceCode": "W2",
Expand Down Expand Up @@ -124,14 +122,62 @@
"releaseDate": "2018-04-19"
},
"offenceHistory": [],
"sentenceTerms": [
{
"bookingId": -2,
"sentenceSequence": 2,
"termSequence": 1,
"sentenceType": "FTR_ORA",
"sentenceTypeDescription": "ORA 28 Day Fixed Term Recall",
"startDate": "2017-05-22",
"years": 2,
"lifeSentence": false,
"caseId": "-2",
"fineAmount": 120.0,
"sentenceTermCode": "IMP",
"lineSeq": 1,
"sentenceStartDate": "2017-07-05"
},
{
"bookingId": -2,
"sentenceSequence": 2,
"termSequence": 2,
"sentenceType": "FTR_ORA",
"sentenceTypeDescription": "ORA 28 Day Fixed Term Recall",
"startDate": "2017-06-22",
"weeks": 2,
"days": 3,
"lifeSentence": false,
"caseId": "-2",
"fineAmount": 120.0,
"sentenceTermCode": "IMP",
"lineSeq": 1,
"sentenceStartDate": "2017-07-05"
},
{
"bookingId": -2,
"sentenceSequence": 2,
"termSequence": 3,
"sentenceType": "FTR_ORA",
"sentenceTypeDescription": "ORA 28 Day Fixed Term Recall",
"startDate": "2017-07-22",
"years": 25,
"lifeSentence": true,
"caseId": "-2",
"fineAmount": 120.0,
"sentenceTermCode": "IMP",
"lineSeq": 1,
"sentenceStartDate": "2017-07-05"
}
],
"aliases": [],
"status": "ACTIVE IN",
"legalStatus": "SENTENCED",
"recall": true,
"imprisonmentStatus": "SENT",
"privilegeSummary": {
"bookingId": -2,
"iepLevel": "Basic",
"iepDate": "2017-09-06",
"iepTime": "2017-09-06T09:44:01"
"iepDate": "2017-09-06"
}
}
Loading

0 comments on commit b9c709f

Please sign in to comment.