Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ applicationinsights-agent-*.jar
*.log

.env
.env-test
AGENTS.md

scripts/
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,22 @@ void shouldCreateProfessionalInformationWithAllValidFields() throws Exception {
final CourtDxCodeDto dxCode1 = new CourtDxCodeDto();
dxCode1.setDxCode("120551 Marylebone 9");
dxCode1.setExplanation("(County Court) primary");
dxCode1.setExplanationCy("(FamilyCourt) primary");

final CourtDxCodeDto dxCode2 = new CourtDxCodeDto();
dxCode2.setDxCode("703360 Hanley 3");
dxCode2.setExplanation("(Crown Court) secondary");
dxCode2.setExplanationCy("(FamilyCourt) secondary");

final CourtFaxDto fax1 = new CourtFaxDto();
fax1.setFaxNumber("0207 222 3333");
fax1.setDescription("General enquiries");
fax1.setDescriptionCy("Ymholiadau cyffredinol");

final CourtFaxDto fax2 = new CourtFaxDto();
fax2.setFaxNumber("0207 444 5555");
fax2.setDescription("Urgent matters");
fax2.setDescriptionCy("Ymholiadau cyffredinol");

final CourtProfessionalInformationDetailsDto professionalInfoDetails =
new CourtProfessionalInformationDetailsDto();
Expand Down Expand Up @@ -204,6 +208,7 @@ void shouldUpdateExistingProfessionalInformation() throws Exception {
final CourtDxCodeDto updatedDxCode = new CourtDxCodeDto();
updatedDxCode.setDxCode("999999 Updated 1");
updatedDxCode.setExplanation("Updated explanation");
updatedDxCode.setExplanationCy("Updated Welsh explanation");

final CourtProfessionalInformationDetailsDto updatedDetails =
new CourtProfessionalInformationDetailsDto();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ private CourtProfessionalInformationDetailsDto sampleProfessionalInformationDeta
CourtDxCodeDto dxCode = CourtDxCodeDto.builder()
.dxCode("444")
.explanation("Main DX")
.explanationCy("Prif DX")
.build();

CourtFaxDto fax = CourtFaxDto.builder()
.faxNumber("01234567890")
.description("Primary fax")
.descriptionCy("Prif ffacs")
.build();

return CourtProfessionalInformationDetailsDto.builder()
Expand All @@ -90,11 +92,13 @@ private CourtProfessionalInformationDetailsDto wrapProfessionalInformation(
CourtDxCodeDto dxCode = CourtDxCodeDto.builder()
.dxCode("444")
.explanation("Main DX")
.explanationCy("Prif DX")
.build();

CourtFaxDto fax = CourtFaxDto.builder()
.faxNumber("01234567890")
.description("Primary fax")
.descriptionCy("Prif ffacs")
.build();

return buildDetails(professionalInformation, codes, List.of(dxCode), List.of(fax));
Expand Down Expand Up @@ -291,10 +295,12 @@ void postProfessionalInformationInvalidDxCodeCharactersReturnsBadRequest() throw
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9$")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

Expand Down Expand Up @@ -322,10 +328,12 @@ void postProfessionalInformationInvalidDxCodeTooLongReturnsBadRequest() throws E
List.of(CourtDxCodeDto.builder()
.dxCode(longCode)
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

Expand Down Expand Up @@ -353,10 +361,12 @@ void postProfessionalInformationInvalidDxExplanationTooLongReturnsBadRequest() t
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation(longExplanation)
.explanationCy("Esboniad hir")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

Expand Down Expand Up @@ -386,10 +396,12 @@ void postProfessionalInformationInvalidGbsReturnsBadRequest() throws Exception {
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

Expand All @@ -416,10 +428,12 @@ void postProfessionalInformationInvalidFaxDescriptionReturnsBadRequest() throws
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Invalid 😊")
.descriptionCy("Ffacs")
.build())
);

Expand All @@ -446,10 +460,12 @@ void postProfessionalInformationInvalidFaxNumberReturnsBadRequest() throws Excep
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("012")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

Expand Down Expand Up @@ -477,6 +493,7 @@ void postProfessionalInformationNullDxEntryReturnsBadRequest() throws Exception
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

Expand All @@ -503,6 +520,7 @@ void postProfessionalInformationNullFaxEntryReturnsBadRequest() throws Exception
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
Arrays.asList((CourtFaxDto) null)
);
Expand All @@ -514,6 +532,130 @@ void postProfessionalInformationNullFaxEntryReturnsBadRequest() throws Exception
.andExpect(jsonPath("$['faxNumbers[0]']").value("must not be null"));
}

@Test
@DisplayName("POST /courts/{courtId}/v1/professional-information returns 400 when DX explanationCy is missing")
void postProfessionalInformationMissingDxExplanationCyReturnsBadRequest() throws Exception {
CourtProfessionalInformationDetailsDto invalid = buildDetails(
ProfessionalInformationDto.builder()
.interviewRooms(true)
.interviewRoomCount(2)
.interviewPhoneNumber("0207 123 4567")
.videoHearings(true)
.commonPlatform(false)
.accessScheme(true)
.build(),
CourtCodesDto.builder().gbs("123").build(),
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

mockMvc.perform(post("/courts/{courtId}/v1/professional-information", courtId)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalid)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$['dxCodes[0].explanationCyPresentWhenExplanationProvided']").exists());
}

@Test
@DisplayName("POST /courts/{courtId}/v1/professional-information returns 400 when fax descriptionCy is missing")
void postProfessionalInformationMissingFaxDescriptionCyReturnsBadRequest() throws Exception {
CourtProfessionalInformationDetailsDto invalid = buildDetails(
ProfessionalInformationDto.builder()
.interviewRooms(true)
.interviewRoomCount(2)
.interviewPhoneNumber("0207 123 4567")
.videoHearings(true)
.commonPlatform(false)
.accessScheme(true)
.build(),
CourtCodesDto.builder().gbs("123").build(),
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.build())
);

mockMvc.perform(post("/courts/{courtId}/v1/professional-information", courtId)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalid)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$['faxNumbers[0].descriptionCyPresentWhenDescriptionProvided']").exists());
}

@Test
@DisplayName("POST /courts/{courtId}/v1/professional-information returns 400 when DX explanation is missing")
void postProfessionalInformationMissingDxExplanationReturnsBadRequest() throws Exception {
CourtProfessionalInformationDetailsDto invalid = buildDetails(
ProfessionalInformationDto.builder()
.interviewRooms(true)
.interviewRoomCount(2)
.interviewPhoneNumber("0207 123 4567")
.videoHearings(true)
.commonPlatform(false)
.accessScheme(true)
.build(),
CourtCodesDto.builder().gbs("123").build(),
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.description("Fax")
.descriptionCy("Ffacs")
.build())
);

mockMvc.perform(post("/courts/{courtId}/v1/professional-information", courtId)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalid)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$['dxCodes[0].explanationCyPresentWhenExplanationProvided']").exists());
}

@Test
@DisplayName("POST /courts/{courtId}/v1/professional-information returns 400 when fax description is missing")
void postProfessionalInformationMissingFaxDescriptionReturnsBadRequest() throws Exception {
CourtProfessionalInformationDetailsDto invalid = buildDetails(
ProfessionalInformationDto.builder()
.interviewRooms(true)
.interviewRoomCount(2)
.interviewPhoneNumber("0207 123 4567")
.videoHearings(true)
.commonPlatform(false)
.accessScheme(true)
.build(),
CourtCodesDto.builder().gbs("123").build(),
List.of(CourtDxCodeDto.builder()
.dxCode("120551 Marylebone 9")
.explanation("Valid explanation")
.explanationCy("Esboniad dilys")
.build()),
List.of(CourtFaxDto.builder()
.faxNumber("0207 111 1111")
.descriptionCy("Ffacs")
.build())
);

mockMvc.perform(post("/courts/{courtId}/v1/professional-information", courtId)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalid)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$['faxNumbers[0].descriptionCyPresentWhenDescriptionProvided']").exists());
}

@Test
@DisplayName("POST /courts/{courtId}/v1/professional-information returns 400 for invalid UUID")
void postProfessionalInformationInvalidUuid() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package uk.gov.hmcts.reform.fact.data.api.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
Expand All @@ -9,6 +10,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import uk.gov.hmcts.reform.fact.data.api.entities.CourtDxCode;
import uk.gov.hmcts.reform.fact.data.api.entities.validation.ValidationConstants;

Expand All @@ -31,10 +33,22 @@ public class CourtDxCodeDto {
message = ValidationConstants.GENERIC_DESCRIPTION_REGEX_MESSAGE)
private String explanation;

@Schema(description = "Welsh language explanation of the DX code")
@Size(max = 250, message = "DX Welsh explanation must be {max} characters or fewer")
@Pattern(regexp = ValidationConstants.GENERIC_DESCRIPTION_REGEX,
message = ValidationConstants.GENERIC_DESCRIPTION_REGEX_MESSAGE)
private String explanationCy;

@AssertTrue(message = "DX explanation and Welsh explanation must be provided together")
public boolean isExplanationCyPresentWhenExplanationProvided() {
return StringUtils.isBlank(explanation) == StringUtils.isBlank(explanationCy);
}

public static CourtDxCodeDto fromEntity(CourtDxCode entity) {
return CourtDxCodeDto.builder()
.dxCode(entity.getDxCode())
.explanation(entity.getExplanation())
.explanationCy(entity.getExplanationCy())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package uk.gov.hmcts.reform.fact.data.api.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
Expand All @@ -9,6 +10,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import uk.gov.hmcts.reform.fact.data.api.entities.CourtFax;
import uk.gov.hmcts.reform.fact.data.api.entities.validation.ValidationConstants;

Expand All @@ -30,10 +32,22 @@ public class CourtFaxDto {
message = ValidationConstants.GENERIC_DESCRIPTION_REGEX_MESSAGE)
private String description;

@Schema(description = "Welsh language fax description")
@Size(max = 250, message = "Welsh fax description must be {max} characters or fewer")
@Pattern(regexp = ValidationConstants.GENERIC_DESCRIPTION_REGEX,
message = ValidationConstants.GENERIC_DESCRIPTION_REGEX_MESSAGE)
private String descriptionCy;

@AssertTrue(message = "Fax description and Welsh fax description must be provided together")
public boolean isDescriptionCyPresentWhenDescriptionProvided() {
return StringUtils.isBlank(description) == StringUtils.isBlank(descriptionCy);
}

public static CourtFaxDto fromEntity(CourtFax entity) {
return CourtFaxDto.builder()
.faxNumber(entity.getFaxNumber())
.description(entity.getDescription())
.descriptionCy(entity.getDescriptionCy())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,11 @@ public class CourtDxCode implements AuditableCourtEntity {
@Column(length = 250)
private String explanation;

@Schema(description = "The Welsh language explanation")
@Size(max = 250)
@Pattern(regexp = ValidationConstants.GENERIC_DESCRIPTION_REGEX,
message = ValidationConstants.GENERIC_DESCRIPTION_REGEX_MESSAGE)
@Column(name = "explanation_cy", length = 250)
private String explanationCy;

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,11 @@ public class CourtFax implements AuditableCourtEntity {
@Column(name = "description", length = 250)
private String description;

@Schema(description = "Welsh language description")
@Size(max = 250, message = "Welsh fax description must be {max} characters or fewer")
@Pattern(regexp = ValidationConstants.GENERIC_DESCRIPTION_REGEX,
message = ValidationConstants.GENERIC_DESCRIPTION_REGEX_MESSAGE)
@Column(name = "description_cy", length = 250)
private String descriptionCy;

}
Loading
Loading