Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
553a579
[DD-42382]- Merge to main cpp-context-hearing
habibulrahaman May 1, 2026
e57f4e7
Merge pull request #124 from hmcts/dev/DD-42382
habibulrahaman May 1, 2026
953dda3
updating poms for 17.104.159-SNAPSHOT development
May 1, 2026
4bc6041
Update core domain version as x.104.
May 1, 2026
4941746
Merge pull request #125 from hmcts/dev/update-core-domain
dabasvijay May 1, 2026
fd9e3ee
updating poms for 17.104.160-SNAPSHOT development
May 1, 2026
66a33ac
updating poms for 17.104.161-SNAPSHOT development
May 2, 2026
a4b56ea
DD-42377 Progression version update
ozgursoftware May 3, 2026
0c97fde
Merge pull request #126 from hmcts/dev/progression-version-update
dabasvijay May 3, 2026
318c899
updating poms for 17.104.161 branch with snapshot versions
May 3, 2026
e38a011
updating poms for 17.104.162-SNAPSHOT development
May 3, 2026
ba5309c
updating poms for branch'dev/release-17.104.161' with non-snapshot ve…
May 3, 2026
6b29770
Merge branch 'dev/release-17.104.161' into dev/release
May 3, 2026
4f1a518
updating develop poms to master versions to avoid merge conflicts
May 3, 2026
81154fe
Merge branch 'dev/release' into main
May 3, 2026
c4ddd4f
Updating develop poms back to pre merge state
May 3, 2026
78034fc
Results validator changes (#137)
sahil-arora-hmcts May 15, 2026
fe35ab7
updating poms for 17.104.162 branch with snapshot versions
May 15, 2026
af99d79
updating poms for 17.104.163-SNAPSHOT development
May 15, 2026
81bab25
updating poms for branch'dev/release-17.104.162' with non-snapshot ve…
May 15, 2026
8276e92
Merge branch 'dev/release-17.104.162' into dev/release
May 15, 2026
ef7bcb7
updating develop poms to master versions to avoid merge conflicts
May 15, 2026
95c16a7
Merge branch 'dev/release' into main
May 15, 2026
a15e136
Updating develop poms back to pre merge state
May 15, 2026
6fd79fd
SNI-8637 Update linked application status when case ejected SNI-7954 …
sevketarisu May 15, 2026
7dbf90b
updating poms for 17.104.164-SNAPSHOT development
May 15, 2026
8183644
CCT-2353 merge to main 2613 release (#151)
jayenhc May 15, 2026
217100f
updating poms for 17.104.164 branch with snapshot versions
May 15, 2026
76595eb
updating poms for 17.104.165-SNAPSHOT development
May 15, 2026
cc803c2
updating poms for branch'dev/release-17.104.164' with non-snapshot ve…
May 15, 2026
88d1a1e
Merge branch 'dev/release-17.104.164' into dev/release
May 15, 2026
69f0c68
updating develop poms to master versions to avoid merge conflicts
May 15, 2026
01b75bd
Merge branch 'dev/release' into main
May 15, 2026
066c447
Updating develop poms back to pre merge state
May 15, 2026
cda3a5e
2613 release fix build (#152)
jayenhc May 15, 2026
6ca423b
updating poms for 17.104.166-SNAPSHOT development
May 15, 2026
a8bd8f8
updating poms for 17.104.166 branch with snapshot versions
May 15, 2026
a557ab7
updating poms for 17.104.167-SNAPSHOT development
May 15, 2026
2f22fef
updating poms for branch'dev/release-17.104.166' with non-snapshot ve…
May 15, 2026
1818d96
Merge branch 'dev/release-17.104.166' into dev/release
May 15, 2026
a3dabb4
updating develop poms to master versions to avoid merge conflicts
May 15, 2026
a7ecbe6
Merge branch 'dev/release' into main
May 15, 2026
b173f2d
Updating develop poms back to pre merge state
May 15, 2026
4b7c096
Tmp/merge to main for 26.13: For Hearing Events, support for a multi-…
arcadiushmcts May 18, 2026
9f0f7b3
updating poms for 17.104.168-SNAPSHOT development
May 18, 2026
1ca2845
updating poms for 17.104.168 branch with snapshot versions
May 18, 2026
48f52bb
updating poms for 17.104.169-SNAPSHOT development
May 18, 2026
b0e5ed5
updating poms for branch'dev/release-17.104.168' with non-snapshot ve…
May 18, 2026
8d1bd01
Merge branch 'dev/release-17.104.168' into dev/release
May 18, 2026
8ba19c7
updating develop poms to master versions to avoid merge conflicts
May 18, 2026
7d8064c
Merge branch 'dev/release' into main
May 18, 2026
48458a7
Updating develop poms back to pre merge state
May 18, 2026
965dd14
pom version
arcadius Jun 4, 2026
71f3aef
Restriction int tests fix
arcadius Jun 3, 2026
af3df32
further int test fixes
arcadius Jun 4, 2026
210292e
Merge pull request #172 from hmcts/tmp/LPT-2325-restrict-int-tests-fix
arcadiushmcts Jun 4, 2026
afb0b3e
further int test fixes
arcadius Jun 4, 2026
b071c1a
Merge branch 'team/LPT-2325-int-tests-fix' into tmp/LPT-2325-restrict…
arcadiushmcts Jun 4, 2026
e14d9f9
Merge pull request #173 from hmcts/tmp/LPT-2325-restrict-int-tests-fix
arcadiushmcts Jun 4, 2026
7312be9
New 17.104.170-lpt2325-SNAPSHOT
Jun 4, 2026
3d02a5a
Update README.md
arcadiushmcts Jun 4, 2026
ffe25c3
Merge pull request #175 from hmcts/arcadiushmcts-patch-dummy-pr
arcadiushmcts Jun 4, 2026
7052ce5
further int test fixes
arcadius Jun 5, 2026
e0b7532
Merge branch 'team/LPT-2325-int-tests-fix' into tmp/LPT-2325-restrict…
arcadiushmcts Jun 5, 2026
bbbd463
Merge pull request #178 from hmcts/tmp/LPT-2325-restrict-int-tests-fix
arcadiushmcts Jun 5, 2026
77ff7a5
further int test fixes
arcadius Jun 5, 2026
fda6933
Merge branch 'team/LPT-2325-int-tests-fix' into tmp/LPT-2325-restrict…
arcadiushmcts Jun 5, 2026
4fb9273
Merge pull request #180 from hmcts/tmp/LPT-2325-restrict-int-tests-fix
arcadiushmcts Jun 5, 2026
9a3fc42
further2 int test fixes
arcadius Jun 5, 2026
e4c90d8
Merge branch 'team/LPT-2325-int-tests-fix' into tmp/LPT-2325-restrict…
arcadiushmcts Jun 5, 2026
6bc45a6
Merge pull request #181 from hmcts/tmp/LPT-2325-restrict-int-tests-fix
arcadiushmcts Jun 5, 2026
8053c2f
New 17.104.171-lpt2325-SNAPSHOT
Jun 5, 2026
732e853
Merge team/LPT-2325-int-tests-fix into dev/SPRDT-870-New (integration…
ozturkmenb Jun 5, 2026
3a618da
Fix timezone flake in HearingServiceTest: stub with UtcClock date to …
ozturkmenb Jun 5, 2026
faaeddb
Fix timezone flake in CustodyTimeLimitCalculatorTest: derive custody …
ozturkmenb Jun 5, 2026
1b85fc9
Merge branch 'team/ccsph2' into dev/SPRDT-870-lpt2325-merge
ozturkmenb Jun 7, 2026
c689c44
updated snapshot version for team branch
ozturkmenb Jun 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hearing-command/hearing-command-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>uk.gov.moj.cpp.hearing</groupId>
<artifactId>hearing-command</artifactId>
<version>17.104.158-SNAPSHOT</version>
<version>17.104.158-CCSPH2-SNAPSHOT</version>
</parent>
<artifactId>hearing-command-api</artifactId>
<packaging>war</packaging>
Expand Down
14 changes: 13 additions & 1 deletion hearing-command/hearing-command-handler/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>uk.gov.moj.cpp.hearing</groupId>
<artifactId>hearing-command</artifactId>
<version>17.104.158-SNAPSHOT</version>
<version>17.104.158-CCSPH2-SNAPSHOT</version>
</parent>
<artifactId>hearing-command-handler</artifactId>
<packaging>war</packaging>
Expand Down Expand Up @@ -92,8 +92,20 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>

<!-- Test Dependencies -->

<dependency>
<groupId>uk.gov.justice.utils</groupId>
<artifactId>test-utils-logging-log4j</artifactId>
<type>pom</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>uk.gov.justice.services</groupId>
<artifactId>test-utils-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@
import static java.util.UUID.fromString;
import static uk.gov.justice.services.core.annotation.Component.COMMAND_HANDLER;

import uk.gov.justice.core.courts.HearingDay;
import uk.gov.justice.services.core.annotation.Handles;
import uk.gov.justice.services.core.annotation.ServiceComponent;
import uk.gov.justice.services.eventsourcing.source.core.exception.EventStreamException;
import uk.gov.justice.services.messaging.JsonEnvelope;
import uk.gov.moj.cpp.hearing.command.handler.service.ReferenceDataService;
import uk.gov.moj.cpp.hearing.command.logEvent.CorrectLogEventCommand;
import uk.gov.moj.cpp.hearing.command.logEvent.CreateHearingEventDefinitionsCommand;
import uk.gov.moj.cpp.hearing.command.logEvent.LogEventCommand;
import uk.gov.moj.cpp.hearing.command.updateEvent.UpdateHearingEventsCommand;
import uk.gov.moj.cpp.hearing.domain.CourtCentre;
import uk.gov.moj.cpp.hearing.domain.aggregate.HearingAggregate;
import uk.gov.moj.cpp.hearing.domain.aggregate.HearingEventDefinitionAggregate;
import uk.gov.moj.cpp.hearing.eventlog.HearingEvent;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import javax.inject.Inject;
import javax.json.JsonArray;
import javax.json.JsonObject;

Expand All @@ -38,6 +44,9 @@ public class HearingEventCommandHandler extends AbstractCommandHandler {

private static final UUID PAUSE_HEARING_EVENT_DEFINITION_ID = UUID.fromString("160ecb51-29ee-4954-bbbf-daab18a24fbb");

@Inject
private ReferenceDataService referenceDataService;

@Handles("hearing.create-hearing-event-definitions")
public void createHearingEventDefinitions(final JsonEnvelope jsonEnvelope) throws EventStreamException {
if (LOGGER.isDebugEnabled()) {
Expand Down Expand Up @@ -94,12 +103,14 @@ public void logHearingEvent(final JsonEnvelope jsonEnvelope) throws EventStreamE
.build();

final UUID activeHearingId = UUID.fromString(activeHearings.getString(index));
final CourtCentre pauseCourtCentre = resolveCourtCentre(activeHearingId, logEventCommand.getEventTime());

aggregate(HearingAggregate.class, activeHearingId, jsonEnvelope, a -> a.logHearingEvent(activeHearingId, PAUSE_HEARING_EVENT_DEFINITION_ID, alterable, defenceCounselId, pauseHearingEvent, hearingTypeIds, userId));
aggregate(HearingAggregate.class, activeHearingId, jsonEnvelope, a -> a.logHearingEvent(activeHearingId, PAUSE_HEARING_EVENT_DEFINITION_ID, alterable, defenceCounselId, pauseHearingEvent, hearingTypeIds, userId, pauseCourtCentre));
}
}

aggregate(HearingAggregate.class, logEventCommand.getHearingId(), jsonEnvelope, a -> a.logHearingEvent(hearingId, hearingEventDefinitionId, alterable, defenceCounselId, hearingEvent, hearingTypeIds, userId));
final CourtCentre courtCentre = resolveCourtCentre(hearingId, logEventCommand.getEventTime());
aggregate(HearingAggregate.class, logEventCommand.getHearingId(), jsonEnvelope, a -> a.logHearingEvent(hearingId, hearingEventDefinitionId, alterable, defenceCounselId, hearingEvent, hearingTypeIds, userId, courtCentre));
}

@Handles("hearing.command.update-hearing-events")
Expand Down Expand Up @@ -130,12 +141,33 @@ public void correctEvent(final JsonEnvelope jsonEnvelope) throws EventStreamExce
.withLastModifiedTime(correctLogEventCommand.getLastModifiedTime())
.withRecordedLabel(correctLogEventCommand.getRecordedLabel())
.withNote(correctLogEventCommand.getNote()).build();
final CourtCentre courtCentre = resolveCourtCentre(correctLogEventCommand.getHearingId(), correctLogEventCommand.getEventTime());
aggregate(HearingAggregate.class, correctLogEventCommand.getHearingId(), jsonEnvelope, a -> a.correctHearingEvent(correctLogEventCommand.getLatestHearingEventId(),
correctLogEventCommand.getHearingId(),
correctLogEventCommand.getHearingEventDefinitionId(),
correctLogEventCommand.getAlterable(),
correctLogEventCommand.getDefenceCounselId(),
hearingEvent,
userId));
userId,
courtCentre));
}

private CourtCentre resolveCourtCentre(final UUID hearingId, final ZonedDateTime eventTime) {
try {
final HearingAggregate aggregate = aggregate(HearingAggregate.class, hearingId);
final Optional<HearingDay> matchedDay = aggregate.findHearingDayFor(eventTime);
if (matchedDay.isEmpty()) {
return null;
}
final UUID centreId = matchedDay.get().getCourtCentreId();
final UUID roomId = matchedDay.get().getCourtRoomId();
if (centreId == null || roomId == null) {
return null;
}
return referenceDataService.resolveCourtCentre(centreId, roomId).orElse(null);
} catch (Exception e) {
LOGGER.warn("Failed to resolve court centre for hearing {} at {}; falling back to top-level", hearingId, eventTime, e);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,20 @@
import uk.gov.moj.cpp.hearing.command.result.SharedResultsCommandResultLineV2;
import uk.gov.moj.cpp.hearing.command.result.UpdateDaysResultLinesStatusCommand;
import uk.gov.moj.cpp.hearing.command.result.UpdateResultLinesStatusCommand;
import uk.gov.moj.cpp.hearing.command.handler.service.validation.ResultsValidator;
import uk.gov.moj.cpp.hearing.command.handler.service.validation.ValidationRequest;
import uk.gov.moj.cpp.hearing.command.handler.service.validation.ValidationRequestMapper;
import uk.gov.moj.cpp.hearing.command.handler.service.validation.ValidationResponse;
import uk.gov.moj.cpp.hearing.domain.aggregate.ApplicationAggregate;
import uk.gov.moj.cpp.hearing.domain.aggregate.HearingAggregate;
import uk.gov.moj.cpp.hearing.domain.event.result.ResultsValidationFailed;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.inject.Inject;
Expand All @@ -56,6 +60,12 @@ public class ShareResultsCommandHandler extends AbstractCommandHandler {
@Inject
private ReferenceDataService referenceDataService;

@Inject
private ResultsValidator resultsValidationClient;

@Inject
private ValidationRequestMapper validationRequestMapper;


@Handles("hearing.command.save-draft-result")
public void saveDraftResult(final JsonEnvelope envelope) throws EventStreamException {
Expand Down Expand Up @@ -174,10 +184,28 @@ public void shareResultForDay(final JsonEnvelope envelope) throws EventStreamExc
}
final ShareDaysResultsCommand command = convertToObject(envelope, ShareDaysResultsCommand.class);
final UUID userId = envelope.metadata().userId().map(UUID::fromString).orElse(null);
long start = System.currentTimeMillis();

final EventStream eventStream = eventSource.getStreamById(command.getHearingId());
final HearingAggregate hearingAggregate = aggregateService.get(eventStream, HearingAggregate.class);

aggregate(HearingAggregate.class, command.getHearingId(), envelope,
aggregate -> shareDaysResultsEnrichedWithYouthCourt(aggregate, command, userId));
final ValidationRequest validationRequest = validationRequestMapper.toValidationRequest(command, hearingAggregate.getHearing());
final String userIdString = userId != null ? userId.toString() : "";

final ValidationResponse validationResponse = resultsValidationClient.validate(validationRequest, userIdString);
long end = System.currentTimeMillis();
LOGGER.info("Validation API call took {} ms for userId={} and for hearingId={}", end - start, userIdString, validationRequest.getHearingId());

if (validationResponse.hasErrors()) {
LOGGER.info("Share blocked by validation errors for hearing {}", command.getHearingId());
final ResultsValidationFailed failedEvent = buildValidationFailedEvent(command, userIdString, validationResponse);
eventStream.append(Stream.of(failedEvent).map(enveloper.withMetadataFrom(envelope)));
return;
}

eventStream.append(
shareDaysResultsEnrichedWithYouthCourt(hearingAggregate, command, userId)
.map(enveloper.withMetadataFrom(envelope)));
}

@Handles("hearing.command.update-result-lines-status")
Expand Down Expand Up @@ -215,6 +243,30 @@ public void replicateAllSharedResultsForHearing(final JsonEnvelope envelope) thr
aggregate -> aggregate.replicateSharedResultsForHearing(hearingId));
}

private ResultsValidationFailed buildValidationFailedEvent(final ShareDaysResultsCommand command,
final String userId,
final ValidationResponse validationResponse) {
return ResultsValidationFailed.builder()
.withHearingId(command.getHearingId())
.withHearingDay(command.getHearingDay())
.withUserId(userId)
.withErrors(validationResponse.getErrors().stream()
.map(e -> new ResultsValidationFailed.ValidationError(
e.getRuleId(), e.getSeverity(), e.getMessage(),
e.getAffectedOffences().stream()
.map(o -> o.getId())
.toList()))
.toList())
.withWarnings(validationResponse.getWarnings().stream()
.map(w -> new ResultsValidationFailed.ValidationError(
w.getRuleId(), w.getSeverity(), w.getMessage(),
w.getAffectedOffences().stream()
.map(o -> o.getId())
.toList()))
.toList())
.build();
}

private Stream<Object> shareResultsEnrichedWithYouthCourt(final HearingAggregate hearingAggregate, final ShareResultsCommand command ) {

final Hearing hearing = hearingAggregate.getHearing();
Expand Down Expand Up @@ -278,7 +330,7 @@ List<CourtApplication> getAdditionalApplications(final Set<UUID> distinctApplica
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
.toList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
import uk.gov.justice.services.messaging.Envelope;
import uk.gov.justice.services.messaging.JsonEnvelope;
import uk.gov.justice.services.messaging.MetadataBuilder;
import uk.gov.moj.cpp.hearing.domain.CourtCentre;

import javax.inject.Inject;
import javax.json.JsonArray;
import javax.json.JsonObject;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;
import static java.util.UUID.randomUUID;
import static uk.gov.justice.services.messaging.JsonObjects.createObjectBuilder;
import static uk.gov.justice.services.core.annotation.Component.COMMAND_API;
Expand Down Expand Up @@ -129,6 +132,72 @@ public void setId(UUID id) {
}


public Optional<CourtCentre> resolveCourtCentre(final UUID courtCentreId, final UUID courtRoomId) {
if (courtCentreId == null || courtRoomId == null) {
return Optional.empty();
}

final JsonArray organisationUnits = queryCourtCentresFor(courtCentreId);
if (organisationUnits == null || organisationUnits.isEmpty()) {
return Optional.empty();
}

return findMatchingOrganisationUnit(organisationUnits, courtCentreId)
.flatMap(ou -> buildCourtCentreFromRoom(ou, courtCentreId, courtRoomId));
}

private JsonArray queryCourtCentresFor(final UUID courtCentreId) {
final JsonObject payload = createObjectBuilder()
.add("courtCentreId", courtCentreId.toString())
.build();

final JsonEnvelope requestEnvelope = envelopeFrom(
metadataBuilder()
.withName(REFERENCEDATA_QUERY_COURT_CENTRES)
.withId(randomUUID())
.build(),
payload);

return requester.requestAsAdmin(requestEnvelope)
.payloadAsJsonObject()
.getJsonArray("organisationunits");
}

private Optional<JsonObject> findMatchingOrganisationUnit(final JsonArray organisationUnits, final UUID courtCentreId) {
final String idAsString = courtCentreId.toString();
return organisationUnits.getValuesAs(JsonObject.class).stream()
.filter(unit -> idAsString.equals(getStringOrNull(unit, "id")))
.findFirst();
}

private Optional<CourtCentre> buildCourtCentreFromRoom(final JsonObject ou, final UUID courtCentreId, final UUID courtRoomId) {
final JsonArray courtrooms = ou.getJsonArray("courtrooms");
if (isNull(courtrooms)) {
return Optional.empty();
}

return courtrooms.getValuesAs(JsonObject.class).stream()
.filter(room -> roomIdMatches(room, courtRoomId))
.findFirst()
.map(room -> CourtCentre.courtCentre()
.withId(courtCentreId)
.withName(getStringOrNull(ou, "oucodeL3Name"))
.withWelshName(getStringOrNull(ou, "oucodeL3WelshName"))
.withRoomId(courtRoomId)
.withRoomName(getStringOrNull(room, "courtroomName"))
.withWelshRoomName(getStringOrNull(room, "welshCourtroomName"))
.build());
}

private static boolean roomIdMatches(final JsonObject room, final UUID courtRoomId) {
final String id = getStringOrNull(room, "id");
return id != null && courtRoomId.equals(UUID.fromString(id));
}

private static String getStringOrNull(final JsonObject json, final String key) {
return json.containsKey(key) ? json.getString(key) : null;
}

public Set<String> retrieveGuiltyPleaTypes() {
final MetadataBuilder metadataBuilder = metadataBuilder()
.withId(randomUUID())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package uk.gov.moj.cpp.hearing.command.handler.service.validation;

public class DefendantDto {
private final String id;
private final String firstName;
private final String lastName;
private final String masterDefendantId;

private DefendantDto(Builder builder) {
this.id = builder.id;
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.masterDefendantId = builder.masterDefendantId;
}

public String getId() {
return id;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public String getMasterDefendantId() {
return masterDefendantId;
}

public static Builder builder() {
return new Builder();
}

public static final class Builder {
private String id;
private String firstName;
private String lastName;
private String masterDefendantId;

public Builder withId(String id) {
this.id = id;
return this;
}

public Builder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}

public Builder withLastName(String lastName) {
this.lastName = lastName;
return this;
}

public Builder withMasterDefendantId(String masterDefendantId) {
this.masterDefendantId = masterDefendantId;
return this;
}

public DefendantDto build() {
return new DefendantDto(this);
}
}
}
Loading
Loading