Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
87d95db
FACT-2551-Welsh-language
debolina-seal Jul 7, 2026
01c904e
functional test fix
debolina-seal Jul 7, 2026
7abbe73
functional test fix
debolina-seal Jul 7, 2026
7139561
testing support change
debolina-seal Jul 7, 2026
add301e
testing support change
debolina-seal Jul 8, 2026
4650fd5
Merge master into FACT-2551-welsh
github-actions[bot] Jul 8, 2026
f9bf7c4
Merge master into FACT-2551-welsh
github-actions[bot] Jul 8, 2026
5e9bef5
Addressing RC
debolina-seal Jul 8, 2026
b1ade77
Merge master into FACT-2551-welsh
github-actions[bot] Jul 9, 2026
6991655
Merge master into FACT-2551-welsh
github-actions[bot] Jul 9, 2026
d16212e
Merge master into FACT-2551-welsh
github-actions[bot] Jul 13, 2026
5c0d227
Merge master into FACT-2551-welsh
github-actions[bot] Jul 13, 2026
98d1c01
Merge master into FACT-2551-welsh
github-actions[bot] Jul 13, 2026
97e25d6
Merge master into FACT-2551-welsh
github-actions[bot] Jul 13, 2026
d0c51d6
Add migration for updating contact description type
debolina-seal Jul 13, 2026
bb7ea7e
Merge master into FACT-2551-welsh
github-actions[bot] Jul 14, 2026
0ce0445
Add migration for updating contact description type
debolina-seal Jul 14, 2026
4e008b7
Merge master into FACT-2551-welsh
github-actions[bot] Jul 14, 2026
54ffb1d
Merge master into FACT-2551-welsh
github-actions[bot] Jul 15, 2026
1d8765b
update wrong translation for contact type
debolina-seal Jul 15, 2026
e6e203d
Merge remote-tracking branch 'origin/FACT-2551-welsh' into FACT-2551-…
debolina-seal Jul 15, 2026
92a08a6
Add migration V1.44 for contact description update
debolina-seal Jul 15, 2026
e7a73a9
Merge master into FACT-2551-welsh
github-actions[bot] Jul 16, 2026
5da8e9e
Merge master into FACT-2551-welsh
github-actions[bot] Jul 16, 2026
456f60c
updated new translation bug 10
debolina-seal Jul 16, 2026
9345f5d
fix sql
debolina-seal Jul 16, 2026
898ab1e
Merge master into FACT-2551-welsh
github-actions[bot] Jul 17, 2026
c2661ce
changed Help with Fees to Help with fees
debolina-seal Jul 20, 2026
dfd7406
changed Help with Fees to Help with fees
debolina-seal Jul 20, 2026
1564e2f
Merge master into FACT-2551-welsh
github-actions[bot] Jul 21, 2026
b6f6575
Merge master into FACT-2551-welsh
github-actions[bot] Jul 21, 2026
738407f
Create V1.45 migration for contact description update
debolina-seal Jul 21, 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
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