From 3a5c06f55283ca3a241a34533b8ac2e6d3df41ab Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Tue, 10 Dec 2024 15:14:23 +0000 Subject: [PATCH 01/15] Added reference summary to open-api-specification.yml Signed-off-by: Jamie Briggs --- data-api/open-api-specification.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/data-api/open-api-specification.yml b/data-api/open-api-specification.yml index f55f45a..3895a3e 100644 --- a/data-api/open-api-specification.yml +++ b/data-api/open-api-specification.yml @@ -954,6 +954,27 @@ paths: description: 'Not found' '500': description: 'Internal server error' + /case-reference: + post: + tags: + - case-reference + summary: 'Get the next available case reference number' + description: get the next available case reference number + operationId: postCaseReference + responses: + '201': + description: 'Successful operation' + content: + application/json: + schema: + $ref: "#/components/schemas/caseReferenceSummary" + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '500': + description: 'Internal server error' + components: securitySchemes: ApiKeyAuth: @@ -1551,6 +1572,11 @@ components: type: 'string' lov_lookup_type: type: 'string' + caseReferenceSummary: + type: 'object' + properties: + case_reference_number: + type: 'string' page: type: 'object' properties: From af29e97b9f4d828947a6062a8b14d3ff4dda74cf Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Tue, 10 Dec 2024 15:35:43 +0000 Subject: [PATCH 02/15] Added CaseReferenceController and NewCaseReferenceRepository Signed-off-by: Jamie Briggs --- .../controller/CaseReferenceController.java | 23 +++++++++++++++ .../laa/ccms/data/entity/CaseReference.java | 27 ++++++++++++++++++ .../NewCaseReferenceRepository.java | 28 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java new file mode 100644 index 0000000..d12578f --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java @@ -0,0 +1,23 @@ +package uk.gov.laa.ccms.data.controller; + +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; +import uk.gov.laa.ccms.data.api.CaseReferenceApi; +import uk.gov.laa.ccms.data.model.CaseReferenceSummary; +import uk.gov.laa.ccms.data.repository.NewCaseReferenceRepository; + +@RestController +@AllArgsConstructor +public class CaseReferenceController implements CaseReferenceApi { + + private final NewCaseReferenceRepository newCaseReferenceRepository; + + @Override + public ResponseEntity postCaseReference() { + // TODO: Need to use a proper mapper still, just testing if this repository works with view + String nextCaseReference = newCaseReferenceRepository.getNextCaseReference(); + return new ResponseEntity<>(new CaseReferenceSummary().caseReferenceNumber(nextCaseReference), HttpStatus.CREATED); + } +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java new file mode 100644 index 0000000..ff92d7e --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java @@ -0,0 +1,27 @@ +package uk.gov.laa.ccms.data.entity; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.io.Serializable; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Immutable; + +@Getter +@EqualsAndHashCode +@Entity +@NoArgsConstructor +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@Table(name = "XXCCMS_GENERATE_V") +@Immutable +public class CaseReference implements Serializable { + + @Id + @Column(name = "NEW_CASE_REFERENCE") + private String caseReference; +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java new file mode 100644 index 0000000..a720208 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java @@ -0,0 +1,28 @@ +package uk.gov.laa.ccms.data.repository; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import uk.gov.laa.ccms.data.entity.CaseReference; + +/** + *

This interface defines a repository for managing CaseReference entities in a read-only manner. + * It extends {@link ReadOnlyRepository} with {@link CaseReference} as the entity type + * and String as the primary key type.

+ * + *

The NewCaseReferenceRepository provides a custom query method to retrieve the next case reference.

+ * + * @author Jamie Briggs + * @see CaseReference + */ +@Repository +public interface NewCaseReferenceRepository +extends ReadOnlyRepository { + + /** + * Retrieves the next case reference from the {@link CaseReference} entity. + * + * @return the next case reference as a {@link String} + */ + @Query("SELECT nextRef.caseReference FROM CaseReference nextRef") + String getNextCaseReference(); +} From 70d39c3dfa0f647736be3fd23030eef692fb8f51 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Wed, 11 Dec 2024 14:15:03 +0000 Subject: [PATCH 03/15] CCMSPUI-378: Added CaseReferenceSummaryMapper and further tests Signed-off-by: Jamie Briggs --- .../controller/CaseReferenceController.java | 18 ++++-- .../laa/ccms/data/entity/CaseReference.java | 10 ++++ .../mapper/CaseReferenceSummaryMapper.java | 30 ++++++++++ .../NewCaseReferenceRepository.java | 9 +-- .../data/service/NewCaseReferenceService.java | 38 ++++++++++++ .../CaseReferenceControllerTest.java | 60 +++++++++++++++++++ .../CaseReferenceSummaryMapperImplTest.java | 26 ++++++++ .../service/NewCaseReferenceServiceTest.java | 40 +++++++++++++ 8 files changed, 222 insertions(+), 9 deletions(-) create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java create mode 100644 data-service/src/test/java/uk/gov/laa/ccms/data/controller/CaseReferenceControllerTest.java create mode 100644 data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java create mode 100644 data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java index d12578f..f1beb71 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/CaseReferenceController.java @@ -6,18 +6,26 @@ import org.springframework.web.bind.annotation.RestController; import uk.gov.laa.ccms.data.api.CaseReferenceApi; import uk.gov.laa.ccms.data.model.CaseReferenceSummary; -import uk.gov.laa.ccms.data.repository.NewCaseReferenceRepository; +import uk.gov.laa.ccms.data.service.NewCaseReferenceService; +/** + * REST Controller responsible for allocating and returning the next case reference number. + * + *

The controller implements the {@link CaseReferenceApi} interface, which defines the API + * contract for working with case references.

+ * + * @author Jamie Briggs + * @see NewCaseReferenceService + */ @RestController @AllArgsConstructor public class CaseReferenceController implements CaseReferenceApi { - private final NewCaseReferenceRepository newCaseReferenceRepository; + private final NewCaseReferenceService newCaseReferenceService; @Override public ResponseEntity postCaseReference() { - // TODO: Need to use a proper mapper still, just testing if this repository works with view - String nextCaseReference = newCaseReferenceRepository.getNextCaseReference(); - return new ResponseEntity<>(new CaseReferenceSummary().caseReferenceNumber(nextCaseReference), HttpStatus.CREATED); + return new ResponseEntity<>((newCaseReferenceService.getNextAvailableCaseReference()), + HttpStatus.CREATED); } } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java index ff92d7e..d7b0825 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/CaseReference.java @@ -12,6 +12,13 @@ import lombok.NoArgsConstructor; import org.hibernate.annotations.Immutable; + +/** + * Represents a case reference from the generate reference view. + * + * @author Jamie Briggs + * @see CaseReference + * */ @Getter @EqualsAndHashCode @Entity @@ -21,6 +28,9 @@ @Immutable public class CaseReference implements Serializable { + /** + * The next available case reference number. + */ @Id @Column(name = "NEW_CASE_REFERENCE") private String caseReference; diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java new file mode 100644 index 0000000..c494dd5 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java @@ -0,0 +1,30 @@ +package uk.gov.laa.ccms.data.mapper; + + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import uk.gov.laa.ccms.data.model.CaseReferenceSummary; + +/** + * Mapper interface for converting a {@link String} value into a {@link CaseReferenceSummary} + * object. + * + * @author Jamie Briggs + * @see Mapper + * @see CaseReferenceSummary + * @see String + */ +@Mapper(componentModel = "spring") +public interface CaseReferenceSummaryMapper { + + /** + * Maps a {@link String} value to a {@link CaseReferenceSummary} object by assigning the value to + * the caseReferenceNumber field. + * + * @param value the input string to be mapped to the caseReferenceNumber field + * @return a {@link CaseReferenceSummary} object containing the given value in the + * caseReferenceNumber field + */ + @Mapping(target = "caseReferenceNumber", source = "value") + CaseReferenceSummary map(String value); +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java index a720208..e94c93d 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NewCaseReferenceRepository.java @@ -6,17 +6,18 @@ /** *

This interface defines a repository for managing CaseReference entities in a read-only manner. - * It extends {@link ReadOnlyRepository} with {@link CaseReference} as the entity type - * and String as the primary key type.

+ * It extends {@link ReadOnlyRepository} with {@link CaseReference} as the entity type + * and String as the primary key type.

* - *

The NewCaseReferenceRepository provides a custom query method to retrieve the next case reference.

+ *

The NewCaseReferenceRepository provides a custom + * query method to retrieve the next case reference.

* * @author Jamie Briggs * @see CaseReference */ @Repository public interface NewCaseReferenceRepository -extends ReadOnlyRepository { + extends ReadOnlyRepository { /** * Retrieves the next case reference from the {@link CaseReference} entity. diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java new file mode 100644 index 0000000..6dd7657 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java @@ -0,0 +1,38 @@ +package uk.gov.laa.ccms.data.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import uk.gov.laa.ccms.data.mapper.CaseReferenceSummaryMapper; +import uk.gov.laa.ccms.data.model.CaseReferenceSummary; +import uk.gov.laa.ccms.data.repository.NewCaseReferenceRepository; + +/** + * Service class for generating and retrieving new case references. + * + *

This service provides a method which allocates and returns the next + * available case reference, mapped using the {@link CaseReferenceSummary}

+ * + * @see Service + * @see CaseReferenceSummary + * @see NewCaseReferenceRepository + * + * @author Jamie Briggs + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class NewCaseReferenceService { + + private final NewCaseReferenceRepository newCaseReferenceRepository; + private final CaseReferenceSummaryMapper caseReferenceSummaryMapper; + + /** + * Retrieves the next available case reference to a {@link CaseReferenceSummary} object. + * + * @return the next available case reference wrapped in a {@link CaseReferenceSummary} object + */ + public CaseReferenceSummary getNextAvailableCaseReference() { + return caseReferenceSummaryMapper.map(newCaseReferenceRepository.getNextCaseReference()); + } +} diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/controller/CaseReferenceControllerTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/controller/CaseReferenceControllerTest.java new file mode 100644 index 0000000..42204ef --- /dev/null +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/controller/CaseReferenceControllerTest.java @@ -0,0 +1,60 @@ +package uk.gov.laa.ccms.data.controller; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.context.WebApplicationContext; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; +import uk.gov.laa.ccms.data.model.CaseReferenceSummary; +import uk.gov.laa.ccms.data.service.NewCaseReferenceService; + +@ExtendWith({SpringExtension.class}) +@ContextConfiguration +@WebAppConfiguration +class CaseReferenceControllerTest { + + @Mock + private NewCaseReferenceService newCaseReferenceService; + + @InjectMocks + private CaseReferenceController caseReferenceController; + + private MockMvc mockMvc; + private ObjectMapper objectMapper; + + @Autowired + WebApplicationContext webApplicationContext; + + @BeforeEach + public void setup(){ + mockMvc = standaloneSetup(caseReferenceController).build(); + objectMapper = new ObjectMapper(); + } + + @Test + void post_returnsData() throws Exception { + // Given + CaseReferenceSummary summary = new CaseReferenceSummary().caseReferenceNumber("123456"); + when(newCaseReferenceService.getNextAvailableCaseReference()).thenReturn(summary); + // Then + String jsonContent = objectMapper.writeValueAsString(summary); + this.mockMvc.perform(post("/case-reference")) + .andDo(print()) + .andExpect(status().isCreated()) + .andExpect(content().json(jsonContent)); + } +} \ No newline at end of file diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java new file mode 100644 index 0000000..269e6e8 --- /dev/null +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java @@ -0,0 +1,26 @@ +package uk.gov.laa.ccms.data.mapper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.laa.ccms.data.model.CaseReferenceSummary; + +@ExtendWith(MockitoExtension.class) +class CaseReferenceSummaryMapperImplTest { + + CaseReferenceSummaryMapper mapper = new CaseReferenceSummaryMapperImpl(); + + @Test + @DisplayName("Should map to CaseReference object") + void shouldMapToCaseReferenceObject(){ + // Given + String referenceNumber = "1234"; + // When + CaseReferenceSummary caseReferenceSummary = mapper.map(referenceNumber); + // Then + assertEquals(referenceNumber, caseReferenceSummary.getCaseReferenceNumber()); + } +} \ No newline at end of file diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java new file mode 100644 index 0000000..919f15f --- /dev/null +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java @@ -0,0 +1,40 @@ +package uk.gov.laa.ccms.data.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.laa.ccms.data.mapper.CaseReferenceSummaryMapper; +import uk.gov.laa.ccms.data.model.CaseReferenceSummary; +import uk.gov.laa.ccms.data.repository.NewCaseReferenceRepository; + +@ExtendWith({MockitoExtension.class}) +class NewCaseReferenceServiceTest { + + @Mock + private NewCaseReferenceRepository newCaseReferenceRepository; + @Mock + private CaseReferenceSummaryMapper caseReferenceSummaryMapper; + + @InjectMocks + private NewCaseReferenceService newCaseReferenceService; + + @Test + @DisplayName("Should return CaseReferenceSummary object") + void shouldReturnCaseReferenceSummaryObject(){ + // Given + when(newCaseReferenceRepository.getNextCaseReference()).thenReturn("123"); + when(caseReferenceSummaryMapper.map("123")).thenReturn(new CaseReferenceSummary().caseReferenceNumber("123")); + // When + CaseReferenceSummary nextAvailableCaseReference + = newCaseReferenceService.getNextAvailableCaseReference(); + // Then + assertEquals("123", nextAvailableCaseReference.getCaseReferenceNumber()); + } + +} \ No newline at end of file From eb151aa77e20276a80e89310822d3cdb66e119ec Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Thu, 12 Dec 2024 10:35:05 +0000 Subject: [PATCH 04/15] CCMSPUI-378: Removed CaseReferenceSummaryMapper.java Signed-off-by: Jamie Briggs --- .../mapper/CaseReferenceSummaryMapper.java | 30 ------------------- .../data/service/NewCaseReferenceService.java | 4 +-- .../CaseReferenceSummaryMapperImplTest.java | 26 ---------------- .../service/NewCaseReferenceServiceTest.java | 4 --- 4 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java delete mode 100644 data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java deleted file mode 100644 index c494dd5..0000000 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package uk.gov.laa.ccms.data.mapper; - - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import uk.gov.laa.ccms.data.model.CaseReferenceSummary; - -/** - * Mapper interface for converting a {@link String} value into a {@link CaseReferenceSummary} - * object. - * - * @author Jamie Briggs - * @see Mapper - * @see CaseReferenceSummary - * @see String - */ -@Mapper(componentModel = "spring") -public interface CaseReferenceSummaryMapper { - - /** - * Maps a {@link String} value to a {@link CaseReferenceSummary} object by assigning the value to - * the caseReferenceNumber field. - * - * @param value the input string to be mapped to the caseReferenceNumber field - * @return a {@link CaseReferenceSummary} object containing the given value in the - * caseReferenceNumber field - */ - @Mapping(target = "caseReferenceNumber", source = "value") - CaseReferenceSummary map(String value); -} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java index 6dd7657..180c01c 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java @@ -3,7 +3,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import uk.gov.laa.ccms.data.mapper.CaseReferenceSummaryMapper; import uk.gov.laa.ccms.data.model.CaseReferenceSummary; import uk.gov.laa.ccms.data.repository.NewCaseReferenceRepository; @@ -25,7 +24,6 @@ public class NewCaseReferenceService { private final NewCaseReferenceRepository newCaseReferenceRepository; - private final CaseReferenceSummaryMapper caseReferenceSummaryMapper; /** * Retrieves the next available case reference to a {@link CaseReferenceSummary} object. @@ -33,6 +31,6 @@ public class NewCaseReferenceService { * @return the next available case reference wrapped in a {@link CaseReferenceSummary} object */ public CaseReferenceSummary getNextAvailableCaseReference() { - return caseReferenceSummaryMapper.map(newCaseReferenceRepository.getNextCaseReference()); + return new CaseReferenceSummary().caseReferenceNumber(newCaseReferenceRepository.getNextCaseReference()); } } diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java deleted file mode 100644 index 269e6e8..0000000 --- a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/CaseReferenceSummaryMapperImplTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package uk.gov.laa.ccms.data.mapper; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import uk.gov.laa.ccms.data.model.CaseReferenceSummary; - -@ExtendWith(MockitoExtension.class) -class CaseReferenceSummaryMapperImplTest { - - CaseReferenceSummaryMapper mapper = new CaseReferenceSummaryMapperImpl(); - - @Test - @DisplayName("Should map to CaseReference object") - void shouldMapToCaseReferenceObject(){ - // Given - String referenceNumber = "1234"; - // When - CaseReferenceSummary caseReferenceSummary = mapper.map(referenceNumber); - // Then - assertEquals(referenceNumber, caseReferenceSummary.getCaseReferenceNumber()); - } -} \ No newline at end of file diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java index 919f15f..641aa6f 100644 --- a/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/service/NewCaseReferenceServiceTest.java @@ -9,7 +9,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import uk.gov.laa.ccms.data.mapper.CaseReferenceSummaryMapper; import uk.gov.laa.ccms.data.model.CaseReferenceSummary; import uk.gov.laa.ccms.data.repository.NewCaseReferenceRepository; @@ -18,8 +17,6 @@ class NewCaseReferenceServiceTest { @Mock private NewCaseReferenceRepository newCaseReferenceRepository; - @Mock - private CaseReferenceSummaryMapper caseReferenceSummaryMapper; @InjectMocks private NewCaseReferenceService newCaseReferenceService; @@ -29,7 +26,6 @@ class NewCaseReferenceServiceTest { void shouldReturnCaseReferenceSummaryObject(){ // Given when(newCaseReferenceRepository.getNextCaseReference()).thenReturn("123"); - when(caseReferenceSummaryMapper.map("123")).thenReturn(new CaseReferenceSummary().caseReferenceNumber("123")); // When CaseReferenceSummary nextAvailableCaseReference = newCaseReferenceService.getNextAvailableCaseReference(); From 00db8816baa3299139c88e345fc7dc97b8dd0ec2 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Thu, 12 Dec 2024 10:40:57 +0000 Subject: [PATCH 05/15] CCMSPUI-378: Fixed checkstyle issue in NewCaseReferenceService Signed-off-by: Jamie Briggs --- .../uk/gov/laa/ccms/data/service/NewCaseReferenceService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java index 180c01c..da1ae6e 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NewCaseReferenceService.java @@ -31,6 +31,7 @@ public class NewCaseReferenceService { * @return the next available case reference wrapped in a {@link CaseReferenceSummary} object */ public CaseReferenceSummary getNextAvailableCaseReference() { - return new CaseReferenceSummary().caseReferenceNumber(newCaseReferenceRepository.getNextCaseReference()); + return new CaseReferenceSummary() + .caseReferenceNumber(newCaseReferenceRepository.getNextCaseReference()); } } From 1c3b01918684a56a5850eeab1ba8bef7ab318e87 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Mon, 16 Dec 2024 16:21:22 +0000 Subject: [PATCH 06/15] CCMSPUI-453: Work towards endpoint and NotificationsMapper including mapping XML values Signed-off-by: Jamie Briggs --- data-api/open-api-specification.yml | 191 ++++++++++++++ data-service/build.gradle | 2 + .../controller/NotificationsController.java | 12 + .../laa/ccms/data/entity/Notification.java | 102 ++++++++ .../ccms/data/mapper/NotificationsMapper.java | 157 +++++++++++ .../data/mapper/xml/AttachedDocumentXml.java | 11 + .../data/mapper/xml/AttachedDocumentsXml.java | 11 + .../mapper/xml/AvailableResponsesXml.java | 11 + .../gov/laa/ccms/data/mapper/xml/NoteXml.java | 12 + .../laa/ccms/data/mapper/xml/NotesXml.java | 12 + .../data/mapper/xml/UploadedDocumentXml.java | 12 + .../data/mapper/xml/UploadedDocumentsXml.java | 11 + .../repository/NotificationRepository.java | 13 + .../data/service/NotificationService.java | 16 ++ .../mapper/NotificationsMapperImplTest.java | 243 ++++++++++++++++++ 15 files changed, 816 insertions(+) create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java create mode 100644 data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java diff --git a/data-api/open-api-specification.yml b/data-api/open-api-specification.yml index 3895a3e..2363ebc 100644 --- a/data-api/open-api-specification.yml +++ b/data-api/open-api-specification.yml @@ -974,6 +974,85 @@ paths: description: 'Forbidden' '500': description: 'Internal server error' + /notifications: + get: + tags: + - notifications + summary: 'Get Notifications' + operationId: 'getNotifications' + x-spring-paginated: true + parameters: + - name: 'case-reference-number' + in: 'query' + schema: + type: 'string' + example: '1234567890' + - name: 'provider-case-reference' + in: 'query' + schema: + type: 'string' + example: "1234567890" + - name: 'assigned-to-user-id' + in: 'query' + schema: + type: 'string' + example: 'abc123' + - name: 'client-surname' + in: 'query' + schema: + type: 'string' + example: 'smith' + - name: 'fee-earner-id' + in: 'query' + schema: + type: 'integer' + example: 1234567890 + - name: 'include-closed' + in: 'query' + schema: + type: boolean + allowEmptyValue: true + - name: 'notification-type' + in: 'query' + schema: + type: 'string' + example: 'A' + - name: 'date-from' + in: 'query' + schema: + type: 'string' + example: "2017-01-01" + format: date + - name: 'date-to' + in: 'query' + schema: + type: 'string' + example: "2017-01-01" + format: date + - name: 'sort' + in: 'query' + schema: + type: 'array' + items: + type: 'string' + - $ref: '#/components/parameters/maxRecords' + responses: + '200': + description: 'Successful operation' + content: + application/json: + schema: + $ref: "#/components/schemas/notifications" + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '404': + description: 'Not found' + '500': + description: 'Internal server error' components: securitySchemes: @@ -981,6 +1060,15 @@ components: type: apiKey in: header name: Authorization + parameters: + maxRecords: + in: query + name: 'max-records' + required: false + schema: + type: 'integer' + default: 100 + example: 123 schemas: baseOffice: type: 'object' @@ -1577,6 +1665,109 @@ components: properties: case_reference_number: type: 'string' + notifications: + allOf: + - $ref: "#/components/schemas/page" + type: object + properties: + content: + type: array + default: [ ] + items: + $ref: '#/components/schemas/notification' + notification: + type: 'object' + properties: + #client_reference_number: + # type: 'string' + #case_reference_number: + # type: 'string' + provider_case_reference_number: + type: 'string' + user: + $ref: '#/components/schemas/userDetail' + client_name: + type: 'string' + category_of_law: + type: 'string' + fee_earner: + type: 'string' + notification_id: + type: 'string' + provider_firm_id: + type: 'string' + subject: + type: 'string' + assign_date: + type: 'string' + format: date + due_date: + type: 'string' + format: date + notification_type: + type: 'string' + status: + type: 'string' + notes: + type: 'array' + items: + $ref: '#/components/schemas/note' + evidence_allowed: + type: 'boolean' + notification_open_indicator: + type: 'boolean' + attached_documents: + type: 'array' + items: + $ref: '#/components/schemas/document' + uploaded_documents: + type: 'array' + items: + $ref: '#/components/schemas/document' + available_responses: + type: array + items: + type: 'string' + note: + type: 'object' + properties: + notes_id: + type: 'string' + user: + $ref: '#/components/schemas/userDetail' + date: + type: 'string' + format: date + message: + type: 'string' + baseDocument: + type: 'object' + properties: + document_type: + type: 'string' + file_extension: + type: 'string' + text: + type: 'string' + document: + allOf: + - $ref: "#/components/schemas/baseDocument" + type: 'object' + properties: + document_id: + type: 'string' + title: + type: 'string' + channel: + type: 'string' + document_link: + type: 'string' + file_data: + type: 'string' + status: + type: 'string' + status_description: + type: 'string' page: type: 'object' properties: diff --git a/data-service/build.gradle b/data-service/build.gradle index 02be09c..8376b3e 100644 --- a/data-service/build.gradle +++ b/data-service/build.gradle @@ -20,6 +20,8 @@ dependencies { implementation 'org.mapstruct:mapstruct:1.5.5.Final' annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.mockito:mockito-core:5.8.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1' diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java index 7d34b1a..9eaa1f4 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java @@ -1,10 +1,14 @@ package uk.gov.laa.ccms.data.controller; +import java.time.LocalDate; +import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; import uk.gov.laa.ccms.data.api.NotificationsApi; import uk.gov.laa.ccms.data.model.NotificationSummary; +import uk.gov.laa.ccms.data.model.Notifications; import uk.gov.laa.ccms.data.service.NotificationService; /** @@ -22,6 +26,14 @@ public class NotificationsController implements NotificationsApi { private final NotificationService notificationService; + @Override + public ResponseEntity getNotifications(String caseReferenceNumber, + String providerCaseReference, String assignedToUserId, String clientSurname, + Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, + LocalDate dateTo, List sort, Integer maxRecords, Pageable pageable) { + return ResponseEntity.ok(notificationService.getNotifications(pageable).get()); + } + @Override public ResponseEntity getUserNotificationSummary(String loginId) { return notificationService.getUserNotificationSummary(loginId).map(ResponseEntity::ok) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java new file mode 100644 index 0000000..7c3884b --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java @@ -0,0 +1,102 @@ +package uk.gov.laa.ccms.data.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.Table; +import java.time.LocalDate; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.hibernate.annotations.Immutable; + +@Entity +@Table(name = "XXCCMS_GET_NOTIFICATIONS_V") +@Getter +@Builder +@Immutable +@AllArgsConstructor +@RequiredArgsConstructor +public class Notification { + + @Id + private long notificationId; + + @Column(name = "ASSIGNED_TO", length = 360) + private String assignedTo; + + @Column(name = "USER_LOGIN_ID", length = 100) + private String userLoginId; + + @Column(name = "PROVIDERFIRM_ID", nullable = false) + private long providerFirmId; + + @Column(name = "CLIENT_PARTY_ID") + private Long clientPartyId; + + @Column(name = "LSC_CASE_REF_REFERENCE", length = 360) + private String lscCaseRefReference; + + @Column(name = "PROVIDER_CASE_REFERENCE", length = 150) + private String providerCaseReference; + + @Column(name = "CLIENT_NAME", length = 301) + private String clientName; + + @Column(name = "CATEGORY_OF_LAW", length = 150) + private String categoryOfLaw; + + @Column(name = "FEE_EARNER", length = 360) + private String feeEarner; + + @Column(name = "FEE_EARNER_PARTY_ID") + private Long feeEarnerPartyId; + + @Column(name = "NOTIFICATION_SUBJECT", length = 320) + private String notificationSubject; + + @Column(name = "DATE_ASSIGNED") + private LocalDate dateAssigned; + + @Column(name = "DUE_DATE") + private LocalDate dueDate; + + @Column(name = "ACTION_NOTIFICATION_IND", length = 150) + String actionNotificationInd; + + @Column(name = "STATUS", length = 150) + String status; + + @Column(name = "EVIDENCE_ALLOWED_IND", length = 5) + String evidenceAllowedInd; + + @Column(name = "IS_OPEN", length = 5) + String isOpen; + + @Column(name = "ASSIGNED_TO_PARTY_ID", precision = 15, scale = 0) + Long assignedToPartyId; + + @Column(name = "PERSON_FIRST_NAME", length = 150) + String personFirstName; + + @Column(name = "PERSON_LAST_NAME", length = 150) + String personLastName; + + @Lob + @Column(name = "NOTES") + String notes; + + @Lob + @Column(name = "UPLOADED_DOCUMENTS") + String uploadedDocuments; + + @Lob + @Column(name = "ATTACHED_DOCUMENTS") + String attachedDocuments; + + @Lob + @Column(name = "AVAILABLE_RESPONSES") + String availableResponses; +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java new file mode 100644 index 0000000..29ac98c --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java @@ -0,0 +1,157 @@ +package uk.gov.laa.ccms.data.mapper; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.util.Collections; +import java.util.List; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.springframework.data.domain.Page; +import uk.gov.laa.ccms.data.entity.Notification; +import uk.gov.laa.ccms.data.mapper.xml.AttachedDocumentXml; +import uk.gov.laa.ccms.data.mapper.xml.AttachedDocumentsXml; +import uk.gov.laa.ccms.data.mapper.xml.AvailableResponsesXml; +import uk.gov.laa.ccms.data.mapper.xml.NoteXml; +import uk.gov.laa.ccms.data.mapper.xml.NotesXml; +import uk.gov.laa.ccms.data.mapper.xml.UploadedDocumentXml; +import uk.gov.laa.ccms.data.mapper.xml.UploadedDocumentsXml; +import uk.gov.laa.ccms.data.model.Document; +import uk.gov.laa.ccms.data.model.Note; +import uk.gov.laa.ccms.data.model.Notifications; +import uk.gov.laa.ccms.data.model.UserDetail; + +/** + * Interface responsible for mapping notification-related data + * entities and models to one another. This interface utilizes MapStruct + * for transformation and supports advanced mappings with custom conversion logic. + * + * @see Notifications + * @see Notification + * @see Page + * @author Jamie Briggs + */ +@Mapper(componentModel = "spring") +public interface NotificationsMapper { + + /** + * Maps a Page of Notification objects to a Notifications object. + * + * @param notificationPage a Page containing Notification entities to be mapped + * @return a Notifications object containing the mapped notifications along with pagination details + */ + Notifications mapToNotificationsList(Page notificationPage); + + /** + * Maps a Notification object to a {@link uk.gov.laa.ccms.data.model.Notification} object. + * + * @param notification the source Notification object to be mapped + * @return the mapped uk.gov.laa.ccms.data.model.Notification object + */ + @Mapping(target = "notes", source = "notes", qualifiedByName = "formatNotes") + @Mapping(target = "uploadedDocuments", source = "uploadedDocuments", qualifiedByName = "formatUploadedDocuments") + @Mapping(target = "attachedDocuments", source = "attachedDocuments", qualifiedByName = "formatAttachedDocuments") + @Mapping(target = "availableResponses", source = "availableResponses", qualifiedByName = "formatResponses") + @Mapping(target = "user.loginId", source = "userLoginId") + @Mapping(target = "user.username", source = "assignedTo") + @Mapping(target = "subject", source = "notificationSubject") + @Mapping(target = "assignDate", source = "dateAssigned") + @Mapping(target = "providerCaseReferenceNumber", source = "providerCaseReference") + @Mapping(target = "notificationType", source = "actionNotificationInd") + @Mapping(target = "notificationOpenIndicator", source = "isOpen") + @Mapping(target = "evidenceAllowed", source = "evidenceAllowedInd") + uk.gov.laa.ccms.data.model.Notification mapToNotification(Notification notification); + + /** + * Maps a String containing XML representation of notes to a List of Note objects. + * + * @param notesString the XML String representing the notes + * @return a List of Note objects derived from the XML String or + * an empty list if the input is null or empty + * @throws JsonProcessingException if an error occurs during the processing of the XML String + */ + @Named("formatNotes") + static List mapToNoteList(String notesString) throws JsonProcessingException { + XmlMapper xmlMapper = getXmlMapper(); + if (notesString == null || notesString.isEmpty()) { + return Collections.emptyList(); + } + List noteXmls = xmlMapper.readValue(notesString, NotesXml.class).noteXmls(); + return noteXmls.stream().map( + x -> new Note().notesId(x.noteId()).user(new UserDetail().username(x.noteBy())) + .date(x.date()).message(x.message())).toList(); + } + + /** + * Maps a String containing the XML representation of uploaded documents to + * a List of {@link Document} objects. + * + * @param uploadedDocuments the XML String representing the uploaded documents + * @return a List of Document objects derived from the XML String or an empty list if the input is null or empty + * @throws JsonProcessingException if an error occurs during the processing of the XML String + */ + @Named("formatUploadedDocuments") + static List mapToFormattedDocuments(String uploadedDocuments) throws JsonProcessingException { + XmlMapper xmlMapper = getXmlMapper(); + if (uploadedDocuments == null || uploadedDocuments.isEmpty()) { + return Collections.emptyList(); + } + List uploadedDocumentsXmls = xmlMapper.readValue(uploadedDocuments, + UploadedDocumentsXml.class).uploadedDocument(); + return uploadedDocumentsXmls.stream().map( + x -> new Document().documentId(x.documentId()).documentType(x.documentType()) + .channel(x.documentChannel()).text(x.text())).toList(); + } + + /** + * Maps a String containing the XML representation of attached documents to a + * List of {@link Document} objects. + * + * @param attachedDocuments the XML String representing the attached documents + * @return a List of Document objects derived from the XML String or an empty list if the input is null or empty + * @throws JsonProcessingException if an error occurs during the processing of the XML String + */ + @Named("formatAttachedDocuments") + static List mapToAttachedDocuments(String attachedDocuments) throws JsonProcessingException { + XmlMapper xmlMapper = getXmlMapper(); + if (attachedDocuments == null || attachedDocuments.isEmpty()) { + return Collections.emptyList(); + } + List uploadedDocumentsXmls = xmlMapper.readValue(attachedDocuments, + AttachedDocumentsXml.class).attachedDocuments(); + return uploadedDocumentsXmls.stream().map( + x -> new Document().documentId(x.documentId()).title(x.attachmentTitle()).text(x.text())).toList(); + } + + /** + * Maps a String containing XML representation of available responses + * to a {@link List} of String objects. + * + * @param availableResponses the XML String representing the available responses + * @return a List of String objects derived from the XML String or an empty list if the input is null or empty + * @throws JsonProcessingException if an error occurs during the processing of the XML String + */ + @Named("formatResponses") + static List mapToAvailableResponses(String availableResponses) + throws JsonProcessingException { + XmlMapper xmlMapper = getXmlMapper(); + if (availableResponses == null || availableResponses.isEmpty()) { + return Collections.emptyList(); + } + return xmlMapper.readValue(availableResponses, + AvailableResponsesXml.class).responses(); + } + + /** + * Creates and configures an instance of XmlMapper. + * + * @return an XmlMapper instance configured with the Java Time Module + */ + private static XmlMapper getXmlMapper() { + XmlMapper xmlMapper = new XmlMapper(); + xmlMapper.registerModule(new JavaTimeModule()); + return xmlMapper; + } +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java new file mode 100644 index 0000000..009ddb1 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java @@ -0,0 +1,11 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public record AttachedDocumentXml( + @JacksonXmlProperty(localName = "document_id") String documentId, + @JacksonXmlProperty(localName = "ATTACHMENT_TITLE") String attachmentTitle, + @JacksonXmlProperty(localName = "Text") String text + ) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java new file mode 100644 index 0000000..5bcf9cb --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java @@ -0,0 +1,11 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import java.util.List; + +public record AttachedDocumentsXml(@JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "Documents") + List attachedDocuments) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java new file mode 100644 index 0000000..c64f202 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java @@ -0,0 +1,11 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import java.util.List; + +public record AvailableResponsesXml(@JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "Response") + List responses) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java new file mode 100644 index 0000000..716af85 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java @@ -0,0 +1,12 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import java.time.LocalDate; + +public record NoteXml(@JacksonXmlProperty(localName = "note_id") String noteId, + @JacksonXmlProperty(localName = "note_by") String noteBy, + @JacksonXmlProperty(localName = "date") + LocalDate date, + @JacksonXmlProperty(localName = "Message") String message) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java new file mode 100644 index 0000000..479d895 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java @@ -0,0 +1,12 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import java.util.List; + +public record NotesXml( + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "Note") + List noteXmls) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java new file mode 100644 index 0000000..bc27531 --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java @@ -0,0 +1,12 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public record UploadedDocumentXml( + @JacksonXmlProperty(localName = "document_id") String documentId, + @JacksonXmlProperty(localName = "document_type") String documentType, + @JacksonXmlProperty(localName = "document_channel") String documentChannel, + @JacksonXmlProperty(localName = "Text") String text +) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java new file mode 100644 index 0000000..a7b0bef --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java @@ -0,0 +1,11 @@ +package uk.gov.laa.ccms.data.mapper.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import java.util.List; + +public record UploadedDocumentsXml(@JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "Documents") + List uploadedDocument) { + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java new file mode 100644 index 0000000..de4518f --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java @@ -0,0 +1,13 @@ +package uk.gov.laa.ccms.data.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; +import uk.gov.laa.ccms.data.entity.Notification; + +@Repository +public interface NotificationRepository extends ReadOnlyRepository { + + Page findByAssignedTo(String assignedTo, Pageable pageable); + Page findAll(Pageable pageable); +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java index 6c3b5ee..bd738cb 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java @@ -4,12 +4,18 @@ import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import uk.gov.laa.ccms.data.entity.Notification; import uk.gov.laa.ccms.data.entity.NotificationCount; import uk.gov.laa.ccms.data.mapper.NotificationSummaryMapper; +import uk.gov.laa.ccms.data.mapper.NotificationsMapper; import uk.gov.laa.ccms.data.model.NotificationSummary; +import uk.gov.laa.ccms.data.model.Notifications; import uk.gov.laa.ccms.data.repository.NotificationCountRepository; +import uk.gov.laa.ccms.data.repository.NotificationRepository; /** * Service class responsible for handling notification-related operations. @@ -27,6 +33,8 @@ public class NotificationService { private final NotificationCountRepository notificationCountRepository; private final NotificationSummaryMapper notificationSummaryMapper; + private final NotificationRepository notificationRepository; + private final NotificationsMapper notificationsMapper; private final UserService userService; /** @@ -47,4 +55,12 @@ public Optional getUserNotificationSummary(String userId) { } return Optional.empty(); } + + public Optional getNotifications(Pageable pageable){ + Page byAssignedTo = notificationRepository.findByAssignedTo( + "PENNY.WALL@SWITALSKIS.COM", pageable); + //Page byAll = notificationRepository.findAll(Pageable.ofSize(100)); + Notifications notifications = notificationsMapper.mapToNotificationsList(byAssignedTo); + return Optional.ofNullable(notifications); + } } diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java new file mode 100644 index 0000000..f9117de --- /dev/null +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java @@ -0,0 +1,243 @@ +package uk.gov.laa.ccms.data.mapper; + + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Collections; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import uk.gov.laa.ccms.data.entity.Notification; +import uk.gov.laa.ccms.data.model.Document; +import uk.gov.laa.ccms.data.model.Note; +import uk.gov.laa.ccms.data.model.Notifications; + +@DisplayName("NotificationsMapperImpl Test") +public class NotificationsMapperImplTest { + + NotificationsMapperImpl mapper = new NotificationsMapperImpl(); + + @Test + @DisplayName("Should map page attributes") + void shouldMapPageAttributes(){ + // Given + Page input = new PageImpl<>(Collections.emptyList(), + PageRequest.of(1, 100), 150); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + assertEquals(1, result.getNumber()); + assertEquals(100, result.getSize()); + assertEquals(2, result.getTotalPages()); + assertEquals(150, result.getTotalElements()); + } + + @Test + @DisplayName("Should map single notification excluding Lob objects") + void shouldMapSingleNotificationExcludingLobObjects(){ + // Given + Notification notification = Notification.builder() + .assignedTo("User Name") + .userLoginId("User Login Id") + .clientName("Client Name") + .categoryOfLaw("Category Of Law") + .feeEarner("Fee Earner") + .notificationId(1L) + .providerFirmId(2L) + .notificationSubject("Notification Subject") + .dateAssigned(LocalDate.of(2024, 1, 1)) + .dueDate(LocalDate.of(2025, 2, 1)) + .status("Status") + .evidenceAllowedInd("true") + .isOpen("true") + .actionNotificationInd("N") + + // Not needed for view model? + .clientPartyId(3L) + .lscCaseRefReference("LSC Case Ref") + .providerCaseReference("Provider Case Ref") + .feeEarnerPartyId(4L) + .assignedToPartyId(5L) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + uk.gov.laa.ccms.data.model.Notification notificationResult = result.getContent().get(0); + assertEquals("User Login Id", notificationResult.getUser().getLoginId()); + assertEquals("User Name", notificationResult.getUser().getUsername()); + assertEquals("Client Name", notificationResult.getClientName()); + assertEquals("Category Of Law", notificationResult.getCategoryOfLaw()); + assertEquals("Fee Earner", notificationResult.getFeeEarner()); + assertEquals("1", notificationResult.getNotificationId()); + assertEquals("2", notificationResult.getProviderFirmId()); + assertEquals("Notification Subject", notificationResult.getSubject()); + assertEquals(LocalDate.of(2024, 1, 1), notificationResult.getAssignDate()); + assertEquals(LocalDate.of(2025, 2, 1), notificationResult.getDueDate()); + assertEquals("N", notificationResult.getNotificationType()); + assertEquals("Status", notificationResult.getStatus()); + assertEquals(true, notificationResult.getEvidenceAllowed()); + assertEquals(true, notificationResult.getNotificationOpenIndicator()); + assertEquals("Provider Case Ref",notificationResult.getProviderCaseReferenceNumber()); + assertEquals(true, notificationResult.getEvidenceAllowed()); + } + + + @Test + @DisplayName("Should map notes") + void shouldMapNotes(){ + // Given + String noteContent = + """ + + + 78405222 + LAA + 2024-12-12 + 12/12/2024 09:16***PENNY.WALL@SWITALSKIS.COM*** Comments: + + LAA Case Reference Number:test + Message for Provider: + + + + + 78405224 + LAA + 2024-12-12 + Unable to send message to conducting solicitor - No live case with the + reference test currently exists. Please either check your records to + ensure you have quoted the correct case reference or check with your conducting + solicitor to ensure that this case has been granted. + + + + """; + Notification notification = Notification.builder() + .notes(noteContent) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + uk.gov.laa.ccms.data.model.Notification notificationResult = result.getContent().get(0); + Note noteOne = notificationResult.getNotes().get(0); + Note noteTwo = notificationResult.getNotes().get(1); + assertEquals("78405222", noteOne.getNotesId()); + assertEquals("LAA", noteOne.getUser().getUsername()); + assertEquals(""" + 12/12/2024 09:16***PENNY.WALL@SWITALSKIS.COM*** Comments: + + LAA Case Reference Number:test + Message for Provider: + + """.strip(), noteOne.getMessage().strip()); + assertEquals(LocalDate.of(2024, 12, 12), noteTwo.getDate()); + assertEquals("78405224", noteTwo.getNotesId()); + assertEquals("LAA", noteTwo.getUser().getUsername()); + assertEquals(""" + Unable to send message to conducting solicitor - No live case with the + reference test currently exists. Please either check your records to + ensure you have quoted the correct case reference or check with your conducting + solicitor to ensure that this case has been granted.""".strip(), noteTwo.getMessage().strip()); + assertEquals(LocalDate.of(2024, 12, 12), noteTwo.getDate()); + + } + + @Test + @DisplayName("Should map uploaded documents") + void shouldMapUploadedDocuments(){ + String uploadedDocumentsString = + """ + + + 33373866 + COURT_ORD + E + 123 + + + 33373867 + COURT_ORD + E + 123 + + + """; + Notification notification = Notification.builder() + .uploadedDocuments(uploadedDocumentsString) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + uk.gov.laa.ccms.data.model.Notification notificationResult = result.getContent().get(0); + Document documentOne = notificationResult.getUploadedDocuments().get(0); + Document documentTwo = notificationResult.getUploadedDocuments().get(1); + assertEquals("33373866", documentOne.getDocumentId()); + assertEquals("COURT_ORD", documentOne.getDocumentType()); + assertEquals("E", documentOne.getChannel()); + assertEquals("123", documentOne.getText()); + assertEquals("33373867", documentTwo.getDocumentId()); + assertEquals("COURT_ORD", documentTwo.getDocumentType()); + assertEquals("E", documentTwo.getChannel()); + assertEquals("123", documentTwo.getText()); + } + + @Test + @DisplayName("Should map attached documents") + void shouldMapAttachedDocuments(){ + String attachedDocuments = + """ + + + 3426023 + Outbound Letter + Bill assessment outcome - sol + + + """; + Notification notification = Notification.builder() + .attachedDocuments(attachedDocuments) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + uk.gov.laa.ccms.data.model.Notification notificationResult = result.getContent().get(0); + Document documentOne = notificationResult.getAttachedDocuments().get(0); + assertEquals("3426023", documentOne.getDocumentId()); + assertEquals("Outbound Letter", documentOne.getTitle()); + assertEquals("Bill assessment outcome - sol", documentOne.getText()); + } + + @Test + @DisplayName("Should map available responses") + void shouldMapAvailableResponses(){ + String attachedDocuments = + """ + + Read + + """; + Notification notification = Notification.builder() + .availableResponses(attachedDocuments) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + uk.gov.laa.ccms.data.model.Notification notificationResult = result.getContent().get(0); + String response = notificationResult.getAvailableResponses().get(0); + assertEquals("Read", response); + } +} From bc4cb349ed4d1a21984c74fc85573317cca66543 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Mon, 16 Dec 2024 16:45:19 +0000 Subject: [PATCH 07/15] CCMSPUI-453: Fix to NotificationsMapper when XML is empty Signed-off-by: Jamie Briggs --- .../ccms/data/mapper/NotificationsMapper.java | 19 +++++- .../mapper/NotificationsMapperImplTest.java | 65 +++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java index 29ac98c..26276fe 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java @@ -79,6 +79,10 @@ static List mapToNoteList(String notesString) throws JsonProcessingExcepti return Collections.emptyList(); } List noteXmls = xmlMapper.readValue(notesString, NotesXml.class).noteXmls(); + + // Return empty list if noteXmls is null + if(noteXmls == null) return Collections.emptyList(); + return noteXmls.stream().map( x -> new Note().notesId(x.noteId()).user(new UserDetail().username(x.noteBy())) .date(x.date()).message(x.message())).toList(); @@ -100,6 +104,10 @@ static List mapToFormattedDocuments(String uploadedDocuments) throws J } List uploadedDocumentsXmls = xmlMapper.readValue(uploadedDocuments, UploadedDocumentsXml.class).uploadedDocument(); + + // Return empty list if uploadedDocumentsXmls is null + if(uploadedDocumentsXmls == null) return Collections.emptyList(); + return uploadedDocumentsXmls.stream().map( x -> new Document().documentId(x.documentId()).documentType(x.documentType()) .channel(x.documentChannel()).text(x.text())).toList(); @@ -119,9 +127,13 @@ static List mapToAttachedDocuments(String attachedDocuments) throws Js if (attachedDocuments == null || attachedDocuments.isEmpty()) { return Collections.emptyList(); } - List uploadedDocumentsXmls = xmlMapper.readValue(attachedDocuments, + List attachedDocumentXmls = xmlMapper.readValue(attachedDocuments, AttachedDocumentsXml.class).attachedDocuments(); - return uploadedDocumentsXmls.stream().map( + + // Return empty list if uploadedDocumentsXmls is null + if(attachedDocumentXmls == null) return Collections.emptyList(); + + return attachedDocumentXmls.stream().map( x -> new Document().documentId(x.documentId()).title(x.attachmentTitle()).text(x.text())).toList(); } @@ -140,8 +152,9 @@ static List mapToAvailableResponses(String availableResponses) if (availableResponses == null || availableResponses.isEmpty()) { return Collections.emptyList(); } - return xmlMapper.readValue(availableResponses, + List responses = xmlMapper.readValue(availableResponses, AvailableResponsesXml.class).responses(); + return responses == null ? Collections.emptyList() : responses; } /** diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java index f9117de..1c879d4 100644 --- a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.LocalDate; import java.util.Arrays; @@ -147,9 +148,25 @@ void shouldMapNotes(){ ensure you have quoted the correct case reference or check with your conducting solicitor to ensure that this case has been granted.""".strip(), noteTwo.getMessage().strip()); assertEquals(LocalDate.of(2024, 12, 12), noteTwo.getDate()); + } + @Test + @DisplayName("Should map empty notes") + void shouldMapEmptyNotes(){ + // Given + String noteContent = ""; + Notification notification = Notification.builder() + .notes(noteContent) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + assertTrue(result.getContent().get(0).getNotes().isEmpty()); } + @Test @DisplayName("Should map uploaded documents") void shouldMapUploadedDocuments(){ @@ -191,6 +208,22 @@ void shouldMapUploadedDocuments(){ assertEquals("123", documentTwo.getText()); } + @Test + @DisplayName("Should map empty uploaded documents") + void shouldMapEmptyUploadedDocuments(){ + // Given + String uploadedDocumentsContent = ""; + Notification notification = Notification.builder() + .uploadedDocuments(uploadedDocumentsContent) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + assertTrue(result.getContent().get(0).getUploadedDocuments().isEmpty()); + } + @Test @DisplayName("Should map attached documents") void shouldMapAttachedDocuments(){ @@ -219,6 +252,22 @@ void shouldMapAttachedDocuments(){ assertEquals("Bill assessment outcome - sol", documentOne.getText()); } + @Test + @DisplayName("Should map empty attached documents") + void shouldMapEmptyAttachedDocuments(){ + // Given + String attachedDocumentsContent = ""; + Notification notification = Notification.builder() + .attachedDocuments(attachedDocumentsContent) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + assertTrue(result.getContent().get(0).getAttachedDocuments().isEmpty()); + } + @Test @DisplayName("Should map available responses") void shouldMapAvailableResponses(){ @@ -240,4 +289,20 @@ void shouldMapAvailableResponses(){ String response = notificationResult.getAvailableResponses().get(0); assertEquals("Read", response); } + + @Test + @DisplayName("Should map empty available responses") + void shouldMapEmptyAvailableResponses(){ + String attachedDocuments = + ""; + Notification notification = Notification.builder() + .availableResponses(attachedDocuments) + .build(); + Page input = new PageImpl<>(Arrays.asList(notification), + PageRequest.of(0, 1), 1); + // When + Notifications result = mapper.mapToNotificationsList(input); + // Then + assertTrue(result.getContent().get(0).getAvailableResponses().isEmpty()); + } } From 71bc49a926a3e0126173ac40e0bcd1e1917dd07f Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Mon, 16 Dec 2024 17:29:32 +0000 Subject: [PATCH 08/15] CCMSPUI-453: Fixes to codestyle violations Signed-off-by: Jamie Briggs --- data-api/open-api-specification.yml | 4 +- .../controller/NotificationsController.java | 13 ++++ .../laa/ccms/data/entity/Notification.java | 12 ++++ .../ccms/data/mapper/NotificationsMapper.java | 70 +++++++++++++------ .../data/mapper/xml/AttachedDocumentXml.java | 15 +++- .../data/mapper/xml/AttachedDocumentsXml.java | 25 ++++++- .../mapper/xml/AvailableResponsesXml.java | 17 ++++- .../gov/laa/ccms/data/mapper/xml/NoteXml.java | 22 ++++-- .../laa/ccms/data/mapper/xml/NotesXml.java | 23 +++++- .../data/mapper/xml/UploadedDocumentXml.java | 18 ++++- .../data/mapper/xml/UploadedDocumentsXml.java | 27 ++++++- .../NotificationCountRepository.java | 4 +- .../repository/NotificationRepository.java | 25 +++++++ .../data/service/NotificationService.java | 9 ++- .../mapper/NotificationsMapperImplTest.java | 5 +- 15 files changed, 243 insertions(+), 46 deletions(-) diff --git a/data-api/open-api-specification.yml b/data-api/open-api-specification.yml index 2363ebc..72d5fc9 100644 --- a/data-api/open-api-specification.yml +++ b/data-api/open-api-specification.yml @@ -1680,8 +1680,8 @@ components: properties: #client_reference_number: # type: 'string' - #case_reference_number: - # type: 'string' + case_reference_number: + type: 'string' provider_case_reference_number: type: 'string' user: diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java index 9eaa1f4..bc9d346 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java @@ -2,13 +2,16 @@ import java.time.LocalDate; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; import uk.gov.laa.ccms.data.api.NotificationsApi; +import uk.gov.laa.ccms.data.model.Notification; import uk.gov.laa.ccms.data.model.NotificationSummary; import uk.gov.laa.ccms.data.model.Notifications; +import uk.gov.laa.ccms.data.model.UserDetail; import uk.gov.laa.ccms.data.service.NotificationService; /** @@ -31,6 +34,16 @@ public ResponseEntity getNotifications(String caseReferenceNumber String providerCaseReference, String assignedToUserId, String clientSurname, Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, LocalDate dateTo, List sort, Integer maxRecords, Pageable pageable) { + // Notification to filter by + Notification notification = new Notification() + .providerCaseReferenceNumber(providerCaseReference) + .clientName(clientSurname) + .feeEarner(Optional.ofNullable(feeEarnerId).map(String::valueOf).orElse("")) + .notificationType(notificationType) + .user( + new UserDetail() + .username(assignedToUserId) + ); return ResponseEntity.ok(notificationService.getNotifications(pageable).get()); } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java index 7c3884b..9fceb17 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java @@ -12,6 +12,18 @@ import lombok.RequiredArgsConstructor; import org.hibernate.annotations.Immutable; +/** + * Represents a notification entity from the "XXCCMS_GET_NOTIFICATIONS_V" database view. + * + *

This entity captures details about notifications, such as the user it is assigned to, + * associated case references, client information, deadlines, and related metadata. + * It provides essential fields to track the status, associated parties, + * supporting documents, and notes.

+ * + *

The class is immutable, and its instances can be created using the builder pattern.

+ * + * @author Jamie Briggs + */ @Entity @Table(name = "XXCCMS_GET_NOTIFICATIONS_V") @Getter diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java index 26276fe..fa74434 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/NotificationsMapper.java @@ -40,7 +40,8 @@ public interface NotificationsMapper { * Maps a Page of Notification objects to a Notifications object. * * @param notificationPage a Page containing Notification entities to be mapped - * @return a Notifications object containing the mapped notifications along with pagination details + * @return a Notifications object containing the mapped notifications along + * with pagination details */ Notifications mapToNotificationsList(Page notificationPage); @@ -51,9 +52,12 @@ public interface NotificationsMapper { * @return the mapped uk.gov.laa.ccms.data.model.Notification object */ @Mapping(target = "notes", source = "notes", qualifiedByName = "formatNotes") - @Mapping(target = "uploadedDocuments", source = "uploadedDocuments", qualifiedByName = "formatUploadedDocuments") - @Mapping(target = "attachedDocuments", source = "attachedDocuments", qualifiedByName = "formatAttachedDocuments") - @Mapping(target = "availableResponses", source = "availableResponses", qualifiedByName = "formatResponses") + @Mapping(target = "uploadedDocuments", source = "uploadedDocuments", + qualifiedByName = "formatUploadedDocuments") + @Mapping(target = "attachedDocuments", source = "attachedDocuments", + qualifiedByName = "formatAttachedDocuments") + @Mapping(target = "availableResponses", source = "availableResponses", + qualifiedByName = "formatResponses") @Mapping(target = "user.loginId", source = "userLoginId") @Mapping(target = "user.username", source = "assignedTo") @Mapping(target = "subject", source = "notificationSubject") @@ -62,6 +66,7 @@ public interface NotificationsMapper { @Mapping(target = "notificationType", source = "actionNotificationInd") @Mapping(target = "notificationOpenIndicator", source = "isOpen") @Mapping(target = "evidenceAllowed", source = "evidenceAllowedInd") + @Mapping(target = "caseReferenceNumber", source = "lscCaseRefReference") uk.gov.laa.ccms.data.model.Notification mapToNotification(Notification notification); /** @@ -69,7 +74,7 @@ public interface NotificationsMapper { * * @param notesString the XML String representing the notes * @return a List of Note objects derived from the XML String or - * an empty list if the input is null or empty + * an empty list if the input is null or empty * @throws JsonProcessingException if an error occurs during the processing of the XML String */ @Named("formatNotes") @@ -78,10 +83,12 @@ static List mapToNoteList(String notesString) throws JsonProcessingExcepti if (notesString == null || notesString.isEmpty()) { return Collections.emptyList(); } - List noteXmls = xmlMapper.readValue(notesString, NotesXml.class).noteXmls(); + List noteXmls = xmlMapper.readValue(notesString, NotesXml.class).notes(); - // Return empty list if noteXmls is null - if(noteXmls == null) return Collections.emptyList(); + // Return empty list if notes is null + if (noteXmls == null) { + return Collections.emptyList(); + } return noteXmls.stream().map( x -> new Note().notesId(x.noteId()).user(new UserDetail().username(x.noteBy())) @@ -90,39 +97,48 @@ static List mapToNoteList(String notesString) throws JsonProcessingExcepti /** * Maps a String containing the XML representation of uploaded documents to - * a List of {@link Document} objects. + * a List of {@link Document} objects. * * @param uploadedDocuments the XML String representing the uploaded documents - * @return a List of Document objects derived from the XML String or an empty list if the input is null or empty + * @return a List of Document objects derived from the XML String or an + * empty list if the input is null or empty * @throws JsonProcessingException if an error occurs during the processing of the XML String */ @Named("formatUploadedDocuments") - static List mapToFormattedDocuments(String uploadedDocuments) throws JsonProcessingException { + static List mapToFormattedDocuments(String uploadedDocuments) + throws JsonProcessingException { XmlMapper xmlMapper = getXmlMapper(); if (uploadedDocuments == null || uploadedDocuments.isEmpty()) { return Collections.emptyList(); } List uploadedDocumentsXmls = xmlMapper.readValue(uploadedDocuments, - UploadedDocumentsXml.class).uploadedDocument(); + UploadedDocumentsXml.class).uploadedDocuments(); // Return empty list if uploadedDocumentsXmls is null - if(uploadedDocumentsXmls == null) return Collections.emptyList(); + if (uploadedDocumentsXmls == null) { + return Collections.emptyList(); + } return uploadedDocumentsXmls.stream().map( - x -> new Document().documentId(x.documentId()).documentType(x.documentType()) - .channel(x.documentChannel()).text(x.text())).toList(); + x -> new Document().documentId(x.documentId()) + .documentType(x.documentType()) + .channel(x.documentChannel()) + .text(x.text())) + .toList(); } /** * Maps a String containing the XML representation of attached documents to a - * List of {@link Document} objects. + * List of {@link Document} objects. * * @param attachedDocuments the XML String representing the attached documents - * @return a List of Document objects derived from the XML String or an empty list if the input is null or empty + * @return a List of Document objects derived from the XML String or an empty + * list if the input is null or empty * @throws JsonProcessingException if an error occurs during the processing of the XML String */ @Named("formatAttachedDocuments") - static List mapToAttachedDocuments(String attachedDocuments) throws JsonProcessingException { + static List mapToAttachedDocuments(String attachedDocuments) + throws JsonProcessingException { XmlMapper xmlMapper = getXmlMapper(); if (attachedDocuments == null || attachedDocuments.isEmpty()) { return Collections.emptyList(); @@ -131,19 +147,27 @@ static List mapToAttachedDocuments(String attachedDocuments) throws Js AttachedDocumentsXml.class).attachedDocuments(); // Return empty list if uploadedDocumentsXmls is null - if(attachedDocumentXmls == null) return Collections.emptyList(); + if (attachedDocumentXmls == null) { + return Collections.emptyList(); + } return attachedDocumentXmls.stream().map( - x -> new Document().documentId(x.documentId()).title(x.attachmentTitle()).text(x.text())).toList(); + x -> new Document() + .documentId(x.documentId()) + .title(x.attachmentTitle()) + .text(x.text())) + .toList(); } /** * Maps a String containing XML representation of available responses - * to a {@link List} of String objects. + * to a {@link List} of String objects. * * @param availableResponses the XML String representing the available responses - * @return a List of String objects derived from the XML String or an empty list if the input is null or empty - * @throws JsonProcessingException if an error occurs during the processing of the XML String + * @return a List of String objects derived from the XML String or an empty + * list if the input is null or empty + * @throws JsonProcessingException if an error occurs during the processing + * of the XML String */ @Named("formatResponses") static List mapToAvailableResponses(String availableResponses) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java index 009ddb1..1aab34a 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentXml.java @@ -2,10 +2,21 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +/** + * Represents a single attached document in XML format. + * + *

This record is primarily utilized for mapping XML data to Java objects + * using the Jackson data format library for XML deserialization/serialization.

+ * + * @param documentId A unique identifier for the document. + * @param attachmentTitle The title of the attached document. + * @param text Text describing the document. + * @see AttachedDocumentsXml + * @author Jamie Briggs + */ public record AttachedDocumentXml( @JacksonXmlProperty(localName = "document_id") String documentId, @JacksonXmlProperty(localName = "ATTACHMENT_TITLE") String attachmentTitle, - @JacksonXmlProperty(localName = "Text") String text - ) { + @JacksonXmlProperty(localName = "Text") String text) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java index 5bcf9cb..6c1053a 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AttachedDocumentsXml.java @@ -4,8 +4,29 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import java.util.List; +/** + * Represents a collection of attached documents in XML format. + * Each document is represented as an instance of the AttachedDocumentXml record. + * + *

The XML structure for this record is defined such that the "Documents" element contains + * a list of attached documents without an additional wrapper element.

+ * + *

This class is primarily used for mapping XML data to Java objects + * using the Jackson data format library.

+ * + *

An attached document typically includes properties such as:

+ *
    + *
  • Document ID: A unique identifier for the document.
  • + *
  • Attachment title: The title of the attached document.
  • + *
  • Text: Text describing the document
  • + *
+ * + * @param attachedDocuments A list of metadata for documents which were attached + * @see AttachedDocumentXml + * @author Jamie Briggs + */ public record AttachedDocumentsXml(@JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "Documents") - List attachedDocuments) { + @JacksonXmlProperty(localName = "Documents") + List attachedDocuments) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java index c64f202..792b9a4 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/AvailableResponsesXml.java @@ -4,8 +4,21 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import java.util.List; +/** + * Represents a collection of available responses in XML format. + * + *

This record maps to an XML structure where the "Response" elements are provided as a list + * without any additional wrapping element. Each entry in the list corresponds to an individual + * response.

+ * + *

It is primarily used for mapping XML data to Java objects + * using the Jackson data format library.

+ * + * @param responses A list of responses available + * @author Jamie Briggs + */ public record AvailableResponsesXml(@JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "Response") - List responses) { + @JacksonXmlProperty(localName = "Response") + List responses) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java index 716af85..0c0e652 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NoteXml.java @@ -3,10 +3,24 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import java.time.LocalDate; +/** + * Represents a single note in XML format. + * + *

This record is used for mapping between XML data and Java objects when handling notes, using + * the Jackson XML data format library. The properties of this record correspond to fields + * in the XML representation.

+ * + * @param noteId A unique identifier for the note. + * @param noteBy The author of the note. + * @param date The date the note was created. + * @param message The contents of the note. + * @see NotesXml + * @author Jamie Briggs + */ public record NoteXml(@JacksonXmlProperty(localName = "note_id") String noteId, - @JacksonXmlProperty(localName = "note_by") String noteBy, - @JacksonXmlProperty(localName = "date") - LocalDate date, - @JacksonXmlProperty(localName = "Message") String message) { + @JacksonXmlProperty(localName = "note_by") String noteBy, + @JacksonXmlProperty(localName = "date") + LocalDate date, + @JacksonXmlProperty(localName = "Message") String message) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java index 479d895..865c749 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/NotesXml.java @@ -4,9 +4,30 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import java.util.List; +/** + * Represents a collection of notes in XML format. + * + *

The XML structure for this record is defined such that the "notes" element contains + * a list of attached notes without an additional wrapper element.

+ * + *

This class is primarily used for mapping XML data to Java objects + * using the Jackson data format library.

+ * + *

A note typically includes properties such as:

+ *
    + *
  • Note ID: A unique identifier for the note.
  • + *
  • Note By: The author of the note.
  • + *
  • Date: The date the note was created.
  • + *
  • Message: The contents of the note
  • + *
+ * + * @see NoteXml + * @param notes A list of notes. + * @author Jamie Briggs + */ public record NotesXml( @JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "Note") - List noteXmls) { + List notes) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java index bc27531..fb8a874 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentXml.java @@ -2,11 +2,25 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +/** + * Represents a single uploaded document in XML format. + * + *

This record is used for mapping XML data to Java objects when handling uploaded documents. + * Each field in this record corresponds to a specific element or attribute in the XML data.

+ * + *

This record is typically part of a collection represented + * by {@link UploadedDocumentsXml}, which aggregates multiple uploaded documents.

+ * + * @param documentId A unique identifier for the document. + * @param documentType The type or category of the document. + * @param documentChannel The source in which the document was uplaoded from. + * @param text Text describing the document. + * @see UploadedDocumentsXml + */ public record UploadedDocumentXml( @JacksonXmlProperty(localName = "document_id") String documentId, @JacksonXmlProperty(localName = "document_type") String documentType, @JacksonXmlProperty(localName = "document_channel") String documentChannel, - @JacksonXmlProperty(localName = "Text") String text -) { + @JacksonXmlProperty(localName = "Text") String text) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java index a7b0bef..9c9ab99 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/mapper/xml/UploadedDocumentsXml.java @@ -4,8 +4,31 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import java.util.List; +/** + * Represents a collection of uploaded documents in XML format. + * + *

This record is used for deserializing and serializing XML data where the "Documents" element + * contains a list of uploaded documents. Each uploaded document is represented as an instance + * of the UploadedDocumentXml record.

+ * + *

The Jackson XML data format library is utilized to map XML structures to Java objects + * and vice versa. The "useWrapping" property is set to false, indicating + * that the "Documents" elements are provided as a flat list without an extra wrapper.

+ * + *

An uploaded document typically includes properties such as:

+ *
    + *
  • Document ID: A unique identifier for the document.
  • + *
  • Document Type: The type or category of the document.
  • + *
  • Document Channel: The source in which the document was uploaded from
  • + *
  • Text: Text describing the document.
  • + *
+ * + * @param uploadedDocuments A list of metadata for documents which were uploaded. + * @see UploadedDocumentXml + * @author Jamie Briggs + */ public record UploadedDocumentsXml(@JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "Documents") - List uploadedDocument) { + @JacksonXmlProperty(localName = "Documents") + List uploadedDocuments) { } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationCountRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationCountRepository.java index 307273e..0538c7e 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationCountRepository.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationCountRepository.java @@ -9,8 +9,8 @@ * Repository interface for accessing {@link NotificationCount} entities. * *

This repository extends the {@link ReadOnlyRepository} interface, it supports read-only - * operations for the {@code NotificationCount} entity, with the primary key of type - * {@code String}.

+ * operations for the {@link NotificationCount} entity, with the primary key of type + * {@link String}.

* * @author Jamie Briggs * @see NotificationCount diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java index de4518f..08d3789 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java @@ -5,9 +5,34 @@ import org.springframework.stereotype.Repository; import uk.gov.laa.ccms.data.entity.Notification; +/** + * Repository interface for accessing {@link Notification} entities. + * + *

This repository extends the {@link ReadOnlyRepository} interface, it supports + * read-only operations for the {@link Notification} entity, with the priary key of type + * {@link Long}.

+ * + * @see Notification + * @see ReadOnlyRepository + * @author Jamie Briggs + */ @Repository public interface NotificationRepository extends ReadOnlyRepository { + /** + * Retrieves a paginated list of notifications assigned to a specific user. + * + * @param assignedTo the identifier of the user to whom notifications are assigned + * @param pageable the pagination information including page number and size + * @return a paginated list of notifications assigned to the specified user + */ Page findByAssignedTo(String assignedTo, Pageable pageable); + + /** + * Retrieves a paginated list of all notifications. + * + * @param pageable the pagination information including page number, size, and sorting + * @return a paginated list of notifications + */ Page findAll(Pageable pageable); } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java index bd738cb..814f900 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java @@ -56,7 +56,14 @@ public Optional getUserNotificationSummary(String userId) { return Optional.empty(); } - public Optional getNotifications(Pageable pageable){ + /** + * Retrieves a paginated list of notifications assigned to a specific user. + * + * @param pageable the pagination and sorting information for retrieving notifications + * @return an Optional containing a Notifications object if + * notifications are found, or an empty Optional otherwise + */ + public Optional getNotifications(Pageable pageable) { Page byAssignedTo = notificationRepository.findByAssignedTo( "PENNY.WALL@SWITALSKIS.COM", pageable); //Page byAll = notificationRepository.findAll(Pageable.ofSize(100)); diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java index 1c879d4..c09c03b 100644 --- a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java @@ -56,11 +56,9 @@ void shouldMapSingleNotificationExcludingLobObjects(){ .evidenceAllowedInd("true") .isOpen("true") .actionNotificationInd("N") - - // Not needed for view model? - .clientPartyId(3L) .lscCaseRefReference("LSC Case Ref") .providerCaseReference("Provider Case Ref") + .clientPartyId(3L) .feeEarnerPartyId(4L) .assignedToPartyId(5L) .build(); @@ -85,6 +83,7 @@ void shouldMapSingleNotificationExcludingLobObjects(){ assertEquals(true, notificationResult.getEvidenceAllowed()); assertEquals(true, notificationResult.getNotificationOpenIndicator()); assertEquals("Provider Case Ref",notificationResult.getProviderCaseReferenceNumber()); + assertEquals("LSC Case Ref", notificationResult.getCaseReferenceNumber()); assertEquals(true, notificationResult.getEvidenceAllowed()); } From d950a148902791d7eb6a11ba103c211a984e40d6 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Tue, 17 Dec 2024 12:23:25 +0000 Subject: [PATCH 09/15] Started on IT for NotificationRepository Signed-off-by: Jamie Briggs --- .gitignore | 4 ++ ...NotificationRepositoryIntegrationTest.java | 44 ++++++++++++++ .../resources/application-h2-test.yml | 6 ++ .../controller/NotificationsController.java | 25 ++++---- .../repository/NotificationRepository.java | 20 ++++--- .../NotificationSpecification.java | 58 +++++++++++++++++++ .../data/service/NotificationService.java | 20 ++++++- 7 files changed, 153 insertions(+), 24 deletions(-) create mode 100644 data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java create mode 100644 data-service/src/integrationTest/resources/application-h2-test.yml create mode 100644 data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java diff --git a/.gitignore b/.gitignore index e3ce445..bdba2a5 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,7 @@ test-results/ .idea /.java-version + +# Project +data-api/src/main/resources/application-secret.yml +data-service/src/main/resources/application-secret.yml diff --git a/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java b/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java new file mode 100644 index 0000000..31e7c6c --- /dev/null +++ b/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java @@ -0,0 +1,44 @@ +package uk.gov.laa.ccms.data.repository; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import uk.gov.laa.ccms.data.entity.Notification; + +@DataJpaTest +@ActiveProfiles("h2-test") +@DisplayName("Notification Repository Integration Test") +public class NotificationRepositoryIntegrationTest { + + @Autowired + private NotificationRepository notificationRepository; + + @PersistenceContext + private EntityManager entityManager; + + + @BeforeEach + void setUp() { + // Insert test data into the in-memory database + Notification n1 = Notification.builder().notificationId(1L).build(); + Notification n2 = Notification.builder().notificationId(2L).build(); + // Use entityManager as NotificationRepository extends ReadOnlyRepository. + entityManager.persist(n1); + entityManager.persist(n2); + } + + @Test + void tempTest(){ + Optional all = notificationRepository.findByNotificationId(1L); + + assertEquals(true, all.isPresent()); + } +} diff --git a/data-service/src/integrationTest/resources/application-h2-test.yml b/data-service/src/integrationTest/resources/application-h2-test.yml new file mode 100644 index 0000000..2021e75 --- /dev/null +++ b/data-service/src/integrationTest/resources/application-h2-test.yml @@ -0,0 +1,6 @@ +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true \ No newline at end of file diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java index bc9d346..7233908 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java @@ -8,10 +8,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; import uk.gov.laa.ccms.data.api.NotificationsApi; -import uk.gov.laa.ccms.data.model.Notification; import uk.gov.laa.ccms.data.model.NotificationSummary; import uk.gov.laa.ccms.data.model.Notifications; -import uk.gov.laa.ccms.data.model.UserDetail; import uk.gov.laa.ccms.data.service.NotificationService; /** @@ -34,17 +32,18 @@ public ResponseEntity getNotifications(String caseReferenceNumber String providerCaseReference, String assignedToUserId, String clientSurname, Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, LocalDate dateTo, List sort, Integer maxRecords, Pageable pageable) { - // Notification to filter by - Notification notification = new Notification() - .providerCaseReferenceNumber(providerCaseReference) - .clientName(clientSurname) - .feeEarner(Optional.ofNullable(feeEarnerId).map(String::valueOf).orElse("")) - .notificationType(notificationType) - .user( - new UserDetail() - .username(assignedToUserId) - ); - return ResponseEntity.ok(notificationService.getNotifications(pageable).get()); + Optional notifications = notificationService.getNotifications( + caseReferenceNumber, + providerCaseReference, + assignedToUserId, + clientSurname, + feeEarnerId, + includeClosed, + notificationType, + dateFrom, + dateTo, + pageable); + return notifications.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build()); } @Override diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java index 08d3789..4b9d3c0 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java @@ -1,7 +1,7 @@ package uk.gov.laa.ccms.data.repository; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; import uk.gov.laa.ccms.data.entity.Notification; @@ -17,22 +17,26 @@ * @author Jamie Briggs */ @Repository -public interface NotificationRepository extends ReadOnlyRepository { +public interface NotificationRepository extends ReadOnlyRepository, + JpaSpecificationExecutor { - /** + Optional findByNotificationId(Long notificationId); + /* + *//** * Retrieves a paginated list of notifications assigned to a specific user. * * @param assignedTo the identifier of the user to whom notifications are assigned * @param pageable the pagination information including page number and size * @return a paginated list of notifications assigned to the specified user - */ + *//* Page findByAssignedTo(String assignedTo, Pageable pageable); - /** + + *//** * Retrieves a paginated list of all notifications. * * @param pageable the pagination information including page number, size, and sorting * @return a paginated list of notifications - */ - Page findAll(Pageable pageable); + *//* + //Page findAll(Pageable pageable);*/ } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java new file mode 100644 index 0000000..d253cfc --- /dev/null +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java @@ -0,0 +1,58 @@ +package uk.gov.laa.ccms.data.repository.specification; + +import jakarta.persistence.criteria.Predicate; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import org.springframework.data.jpa.domain.Specification; +import uk.gov.laa.ccms.data.entity.Notification; + +public class NotificationSpecification { + + public static Specification withFilters( + String caseReferenceNumber, + String providerCaseReference, String assignedToUserId, String clientSurname, + Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, + LocalDate dateTo + ){ + return (root, query, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + + // Add predicates for each filter only if they are non-null + if (caseReferenceNumber != null) { + predicates.add(criteriaBuilder.equal(root.get("caseReferenceNumber"), caseReferenceNumber)); + } + if (providerCaseReference != null) { + predicates.add(criteriaBuilder.equal(root.get("providerCaseReference"), providerCaseReference)); + } + if (assignedToUserId != null) { + predicates.add(criteriaBuilder.equal(root.get("assignedTo"), assignedToUserId)); + } + if (clientSurname != null) { + predicates.add(criteriaBuilder.like(root.get("clientName"), "%" + clientSurname + "%")); + } + if (feeEarnerId != null) { + predicates.add(criteriaBuilder.equal(root.get("feeEarnerId"), feeEarnerId)); + } + if (includeClosed != null) { + if (!includeClosed) { + predicates.add(criteriaBuilder.isFalse(root.get("isClosed"))); + } + } + if (notificationType != null) { + predicates.add(criteriaBuilder.equal(root.get("notificationType"), notificationType)); + } + if (dateFrom != null) { + predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("date"), dateFrom)); + } + if (dateTo != null) { + predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("date"), dateTo)); + } + + // Combine all predicates with AND + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + +} diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java index 814f900..b50559f 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java @@ -1,5 +1,6 @@ package uk.gov.laa.ccms.data.service; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -16,6 +17,7 @@ import uk.gov.laa.ccms.data.model.Notifications; import uk.gov.laa.ccms.data.repository.NotificationCountRepository; import uk.gov.laa.ccms.data.repository.NotificationRepository; +import uk.gov.laa.ccms.data.repository.specification.NotificationSpecification; /** * Service class responsible for handling notification-related operations. @@ -63,9 +65,21 @@ public Optional getUserNotificationSummary(String userId) { * @return an Optional containing a Notifications object if * notifications are found, or an empty Optional otherwise */ - public Optional getNotifications(Pageable pageable) { - Page byAssignedTo = notificationRepository.findByAssignedTo( - "PENNY.WALL@SWITALSKIS.COM", pageable); + public Optional getNotifications(String caseReferenceNumber, + String providerCaseReference, String assignedToUserId, String clientSurname, + Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, + LocalDate dateTo, Pageable pageable) { + Page byAssignedTo = notificationRepository.findAll( + NotificationSpecification.withFilters(caseReferenceNumber, + providerCaseReference, + assignedToUserId, + clientSurname, + feeEarnerId, + includeClosed, + notificationType, + dateFrom, + dateTo), + pageable); //Page byAll = notificationRepository.findAll(Pageable.ofSize(100)); Notifications notifications = notificationsMapper.mapToNotificationsList(byAssignedTo); return Optional.ofNullable(notifications); From 2799af61d82fb4aabeb80f45ff307e1a766127bc Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Tue, 17 Dec 2024 15:39:19 +0000 Subject: [PATCH 10/15] Added NotificationSpecification to help with filtering Notification entities in NotificationRepository Signed-off-by: Jamie Briggs --- ...NotificationRepositoryIntegrationTest.java | 334 +++++++++++++++++- .../laa/ccms/data/entity/Notification.java | 24 +- .../repository/NotificationRepository.java | 31 +- .../NotificationSpecification.java | 22 +- .../mapper/NotificationsMapperImplTest.java | 2 +- 5 files changed, 351 insertions(+), 62 deletions(-) diff --git a/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java b/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java index 31e7c6c..3e17e14 100644 --- a/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java +++ b/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java @@ -4,14 +4,18 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import java.util.Optional; +import java.time.LocalDate; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.test.context.ActiveProfiles; import uk.gov.laa.ccms.data.entity.Notification; +import uk.gov.laa.ccms.data.repository.specification.NotificationSpecification; @DataJpaTest @ActiveProfiles("h2-test") @@ -23,22 +27,338 @@ public class NotificationRepositoryIntegrationTest { @PersistenceContext private EntityManager entityManager; - + + private Notification n1; + private Notification n2; @BeforeEach void setUp() { // Insert test data into the in-memory database - Notification n1 = Notification.builder().notificationId(1L).build(); - Notification n2 = Notification.builder().notificationId(2L).build(); + n1 = Notification.builder().notificationId(1L) + .lscCaseRefReference("1001") + .providerCaseReference("2001") + .assignedTo("JBriggs") + .personFirstName("Jamie") + .personLastName("Briggs") + .feeEarnerPartyId(3001L) + .isOpen(true) + .actionNotificationInd("N") + .dateAssigned(LocalDate.of(2025, 1, 1)) + .build(); + n2 = Notification.builder().notificationId(2L) + .lscCaseRefReference("1002") + .providerCaseReference("2002") + .assignedTo("SMonday") + .personFirstName("Ski") + .personLastName("Bri-Monday") + .feeEarnerPartyId(3002L) + .isOpen(false) + .actionNotificationInd("O") + .dateAssigned(LocalDate.of(2026, 1, 1)) + .build(); // Use entityManager as NotificationRepository extends ReadOnlyRepository. entityManager.persist(n1); entityManager.persist(n2); } @Test - void tempTest(){ - Optional all = notificationRepository.findByNotificationId(1L); + @DisplayName("Should get all Notifications") + void shouldGetAllNotifications(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(2, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + assertEquals(true, result.getContent().contains(n2)); + } + + @Test + @DisplayName("Should filter by case reference number") + void shouldFilterByCaseReferenceNumber(){ + // Given + Specification spec = NotificationSpecification.withFilters( + "1001", + null, + null, + null, + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + } + + @Test + @DisplayName("Should filter by similar case reference number") + void shouldFilterBySimilarCaseReferenceNumber(){ + // Given + Specification spec = NotificationSpecification.withFilters( + "100", + null, + null, + null, + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(2, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + assertEquals(true, result.getContent().contains(n2)); + } + + @Test + @DisplayName("Should filter by provider case reference number") + void shouldFilterByProviderCaseReferenceNumber(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + "2001", + null, + null, + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + } + + @Test + @DisplayName("Should filter by similar provider case reference number") + void shouldFilterBySimilarProviderCaseReferenceNumber(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + "200", + null, + null, + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(2, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + assertEquals(true, result.getContent().contains(n2)); + } + + @Test + @DisplayName("Should filter by assigned to user ID") + void shouldFilterByAssignedToUserID(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + "JBriggs", + null, + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + } + + @Test + @DisplayName("Should filter by user surname") + void shouldFilterByUserSurname(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + "Briggs", + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + } + + @Test + @DisplayName("Should filter by like user surname") + void shouldFilterByLikeUserSurname(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + "Bri", + null, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(2, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + assertEquals(true, result.getContent().contains(n2)); + } - assertEquals(true, all.isPresent()); + @Test + @DisplayName("Should filter by fee earner ID") + void shouldFilterByFeeEarnerID(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + 3001, + true, + null, + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); } + + @Test + @DisplayName("Should filter by notification type") + void shouldFilterByNotificationType(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + null, + false, "N", + null, + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + } + + @Test + @DisplayName("Should filter by date from") + void shouldFilterByDateFrom(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + null, + true, + null, + LocalDate.of(2025, 2, 1), + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n2)); + } + + @Test + @DisplayName("Should filter by date from inclusive") + void shouldFilterByDateFromInclusive(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + null, + true, + null, + LocalDate.of(2024, 1, 1), + null); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(2, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + assertEquals(true, result.getContent().contains(n2)); + } + + @Test + @DisplayName("Should filter by date to") + void shouldFilterByDateTo(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + null, + true, + null, + null, + LocalDate.of(2025, 12, 1)); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(1, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + } + + @Test + @DisplayName("Should filter by date to inclusive") + void shouldFilterByDateToInclusive(){ + // Given + Specification spec = NotificationSpecification.withFilters( + null, + null, + null, + null, + null, + true, + null, + null, + LocalDate.of(2026, 1, 1)); + // When + Page result = notificationRepository.findAll(spec, Pageable.unpaged()); + // Then + assertEquals(2, result.getTotalElements()); + assertEquals(true, result.getContent().contains(n1)); + assertEquals(true, result.getContent().contains(n2)); + } + + } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java index 9fceb17..56fa671 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/entity/Notification.java @@ -76,39 +76,39 @@ public class Notification { private LocalDate dueDate; @Column(name = "ACTION_NOTIFICATION_IND", length = 150) - String actionNotificationInd; + private String actionNotificationInd; @Column(name = "STATUS", length = 150) - String status; + private String status; @Column(name = "EVIDENCE_ALLOWED_IND", length = 5) - String evidenceAllowedInd; + private String evidenceAllowedInd; - @Column(name = "IS_OPEN", length = 5) - String isOpen; + @Column(name = "IS_OPEN") + private Boolean isOpen; @Column(name = "ASSIGNED_TO_PARTY_ID", precision = 15, scale = 0) - Long assignedToPartyId; + private Long assignedToPartyId; @Column(name = "PERSON_FIRST_NAME", length = 150) - String personFirstName; + private String personFirstName; @Column(name = "PERSON_LAST_NAME", length = 150) - String personLastName; + private String personLastName; @Lob @Column(name = "NOTES") - String notes; + private String notes; @Lob @Column(name = "UPLOADED_DOCUMENTS") - String uploadedDocuments; + private String uploadedDocuments; @Lob @Column(name = "ATTACHED_DOCUMENTS") - String attachedDocuments; + private String attachedDocuments; @Lob @Column(name = "AVAILABLE_RESPONSES") - String availableResponses; + private String availableResponses; } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java index 4b9d3c0..28bf337 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java @@ -1,42 +1,13 @@ package uk.gov.laa.ccms.data.repository; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; import uk.gov.laa.ccms.data.entity.Notification; -/** - * Repository interface for accessing {@link Notification} entities. - * - *

This repository extends the {@link ReadOnlyRepository} interface, it supports - * read-only operations for the {@link Notification} entity, with the priary key of type - * {@link Long}.

- * - * @see Notification - * @see ReadOnlyRepository - * @author Jamie Briggs - */ + @Repository public interface NotificationRepository extends ReadOnlyRepository, JpaSpecificationExecutor { - Optional findByNotificationId(Long notificationId); - /* - *//** - * Retrieves a paginated list of notifications assigned to a specific user. - * - * @param assignedTo the identifier of the user to whom notifications are assigned - * @param pageable the pagination information including page number and size - * @return a paginated list of notifications assigned to the specified user - *//* - Page findByAssignedTo(String assignedTo, Pageable pageable); - - *//** - * Retrieves a paginated list of all notifications. - * - * @param pageable the pagination information including page number, size, and sorting - * @return a paginated list of notifications - *//* - //Page findAll(Pageable pageable);*/ } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java index d253cfc..2e2e756 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java @@ -12,7 +12,7 @@ public class NotificationSpecification { public static Specification withFilters( String caseReferenceNumber, String providerCaseReference, String assignedToUserId, String clientSurname, - Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, + Integer feeEarnerId, boolean includeClosed, String notificationType, LocalDate dateFrom, LocalDate dateTo ){ return (root, query, criteriaBuilder) -> { @@ -20,33 +20,31 @@ public static Specification withFilters( // Add predicates for each filter only if they are non-null if (caseReferenceNumber != null) { - predicates.add(criteriaBuilder.equal(root.get("caseReferenceNumber"), caseReferenceNumber)); + predicates.add(criteriaBuilder.like(root.get("lscCaseRefReference"), "%" + caseReferenceNumber + "%")); } if (providerCaseReference != null) { - predicates.add(criteriaBuilder.equal(root.get("providerCaseReference"), providerCaseReference)); + predicates.add(criteriaBuilder.like(root.get("providerCaseReference"), "%" + providerCaseReference + "%")); } if (assignedToUserId != null) { predicates.add(criteriaBuilder.equal(root.get("assignedTo"), assignedToUserId)); } if (clientSurname != null) { - predicates.add(criteriaBuilder.like(root.get("clientName"), "%" + clientSurname + "%")); + predicates.add(criteriaBuilder.like(root.get("personLastName"), "%" + clientSurname + "%")); } if (feeEarnerId != null) { - predicates.add(criteriaBuilder.equal(root.get("feeEarnerId"), feeEarnerId)); + predicates.add(criteriaBuilder.equal(root.get("feeEarnerPartyId"), feeEarnerId)); } - if (includeClosed != null) { - if (!includeClosed) { - predicates.add(criteriaBuilder.isFalse(root.get("isClosed"))); - } + if (!includeClosed) { + predicates.add(criteriaBuilder.isTrue(root.get("isOpen"))); } if (notificationType != null) { - predicates.add(criteriaBuilder.equal(root.get("notificationType"), notificationType)); + predicates.add(criteriaBuilder.equal(root.get("actionNotificationInd"), notificationType)); } if (dateFrom != null) { - predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("date"), dateFrom)); + predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("dateAssigned"), dateFrom)); } if (dateTo != null) { - predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("date"), dateTo)); + predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("dateAssigned"), dateTo)); } // Combine all predicates with AND diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java index c09c03b..7f9bd1f 100644 --- a/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/mapper/NotificationsMapperImplTest.java @@ -54,7 +54,7 @@ void shouldMapSingleNotificationExcludingLobObjects(){ .dueDate(LocalDate.of(2025, 2, 1)) .status("Status") .evidenceAllowedInd("true") - .isOpen("true") + .isOpen(true) .actionNotificationInd("N") .lscCaseRefReference("LSC Case Ref") .providerCaseReference("Provider Case Ref") From 57805eb66547ec539692f3b56310d1f9b8ea62d0 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Tue, 17 Dec 2024 16:30:08 +0000 Subject: [PATCH 11/15] CCMSPUI-453: Tweaks to open-api-specification.yml, and NotificationControllerTests Signed-off-by: Jamie Briggs --- data-api/open-api-specification.yml | 18 +--------- .../controller/NotificationsController.java | 28 +++++++++++++-- .../data/service/NotificationService.java | 2 +- .../NotificationsControllerTest.java | 35 ++++++++++++++++++- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/data-api/open-api-specification.yml b/data-api/open-api-specification.yml index 72d5fc9..863c668 100644 --- a/data-api/open-api-specification.yml +++ b/data-api/open-api-specification.yml @@ -1011,7 +1011,7 @@ paths: in: 'query' schema: type: boolean - allowEmptyValue: true + default: true - name: 'notification-type' in: 'query' schema: @@ -1029,13 +1029,6 @@ paths: type: 'string' example: "2017-01-01" format: date - - name: 'sort' - in: 'query' - schema: - type: 'array' - items: - type: 'string' - - $ref: '#/components/parameters/maxRecords' responses: '200': description: 'Successful operation' @@ -1060,15 +1053,6 @@ components: type: apiKey in: header name: Authorization - parameters: - maxRecords: - in: query - name: 'max-records' - required: false - schema: - type: 'integer' - default: 100 - example: 123 schemas: baseOffice: type: 'object' diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java index 7233908..9b27175 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/controller/NotificationsController.java @@ -1,7 +1,6 @@ package uk.gov.laa.ccms.data.controller; import java.time.LocalDate; -import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; @@ -27,18 +26,34 @@ public class NotificationsController implements NotificationsApi { private final NotificationService notificationService; + /** + * Retrieves a list of notifications based on various search criteria. + * + * @param caseReferenceNumber the case reference number to filter notifications + * @param providerCaseReference the provider-specific case reference to filter notifications + * @param assignedToUserId the user ID to filter notifications assigned to a specific user + * @param clientSurname the client's surname to filter notifications for a specific client + * @param feeEarnerId the ID of the fee earner to filter notifications associated with them + * @param includeClosed a flag to indicate whether to include closed notifications in the results + * @param notificationType the type of notifications to filter by + * @param dateFrom the starting date to filter notifications by a specific date range + * @param dateTo the ending date to filter notifications by a specific date range + * @param pageable the pagination and sorting information for the result set + * @return a {@code ResponseEntity} containing the retrieved list of notifications if found, + * or a {@code ResponseEntity} with HTTP status 404 if no notifications are found + */ @Override public ResponseEntity getNotifications(String caseReferenceNumber, String providerCaseReference, String assignedToUserId, String clientSurname, Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, - LocalDate dateTo, List sort, Integer maxRecords, Pageable pageable) { + LocalDate dateTo, Pageable pageable) { Optional notifications = notificationService.getNotifications( caseReferenceNumber, providerCaseReference, assignedToUserId, clientSurname, feeEarnerId, - includeClosed, + Boolean.TRUE.equals(includeClosed), notificationType, dateFrom, dateTo, @@ -46,6 +61,13 @@ public ResponseEntity getNotifications(String caseReferenceNumber return notifications.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build()); } + /** + * Retrieves a summary of user notifications for the specified login ID. + * + * @param loginId the login ID of the user for whom the notification summary is to be retrieved + * @return a {@code ResponseEntity} containing the {@code NotificationSummary} if found, + * or a {@code ResponseEntity} with HTTP status 404 if no summary is available + */ @Override public ResponseEntity getUserNotificationSummary(String loginId) { return notificationService.getUserNotificationSummary(loginId).map(ResponseEntity::ok) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java index b50559f..c3d9c76 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java @@ -67,7 +67,7 @@ public Optional getUserNotificationSummary(String userId) { */ public Optional getNotifications(String caseReferenceNumber, String providerCaseReference, String assignedToUserId, String clientSurname, - Integer feeEarnerId, Boolean includeClosed, String notificationType, LocalDate dateFrom, + Integer feeEarnerId, boolean includeClosed, String notificationType, LocalDate dateFrom, LocalDate dateTo, Pageable pageable) { Page byAssignedTo = notificationRepository.findAll( NotificationSpecification.withFilters(caseReferenceNumber, diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/controller/NotificationsControllerTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/controller/NotificationsControllerTest.java index 1cd349d..16a7f03 100644 --- a/data-service/src/test/java/uk/gov/laa/ccms/data/controller/NotificationsControllerTest.java +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/controller/NotificationsControllerTest.java @@ -14,14 +14,18 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; +import uk.gov.laa.ccms.data.model.Notification; import uk.gov.laa.ccms.data.model.NotificationSummary; +import uk.gov.laa.ccms.data.model.Notifications; import uk.gov.laa.ccms.data.service.NotificationService; @ExtendWith({SpringExtension.class}) @@ -44,7 +48,9 @@ class NotificationsControllerTest { @BeforeEach public void setup() { - mockMvc = standaloneSetup(notificationsController).build(); + mockMvc = standaloneSetup(notificationsController) + .setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver()) + .build(); objectMapper = new ObjectMapper(); } @@ -74,4 +80,31 @@ void getUserNotificationSummary_notFound() throws Exception { .andDo(print()) .andExpect(status().isNotFound()); } + + @Test + @DisplayName("getNotifications: Returns data") + void getNotifications_returnsData() throws Exception { + //Given + Notifications expected = new Notifications().addContentItem(new Notification().notificationId("123")); + when(notificationService.getNotifications(Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any(), Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any(), + Mockito.any(), Mockito.any())).thenReturn(Optional.of( + expected)); + // Then + String jsonContent = objectMapper.writeValueAsString(expected); + this.mockMvc.perform(get("/notifications")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().json(jsonContent)); + } + + @Test + @DisplayName("getNotifications: Not found") + void getNotifications_notFound() throws Exception { + //Given + // Then + this.mockMvc.perform(get("/notifications")) + .andDo(print()) + .andExpect(status().isNotFound()); + } } \ No newline at end of file From c9b46466ee8d4a4de850e3d782066b50b27c0622 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Tue, 17 Dec 2024 17:55:30 +0000 Subject: [PATCH 12/15] CCMSPUI-453: NotificationServiceTest and additional JavaDoc Signed-off-by: Jamie Briggs --- .../repository/NotificationRepository.java | 15 +- .../NotificationSpecification.java | 58 +++++++- .../data/service/NotificationService.java | 17 ++- .../data/service/NotificationServiceTest.java | 130 ++++++++++++++++++ 4 files changed, 211 insertions(+), 9 deletions(-) create mode 100644 data-service/src/test/java/uk/gov/laa/ccms/data/service/NotificationServiceTest.java diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java index 28bf337..06c342b 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/NotificationRepository.java @@ -5,9 +5,22 @@ import uk.gov.laa.ccms.data.entity.Notification; +/** + * Repository interface for accessing {@link Notification} entities. + * + *

This repository extends the {@link ReadOnlyRepository} interface, + * it supports read-only operations for the {@link Notification} entity. + * This repository also extends {@link JpaSpecificationExecutor}, which + * allows the use of ${@link org.springframework.data.jpa.domain.Specification} + * to filter easier.

+ * + * @author Jamie Briggs + * @see Notification + * @see ReadOnlyRepository + * @see org.springframework.data.jpa.domain.Specification + */ @Repository public interface NotificationRepository extends ReadOnlyRepository, JpaSpecificationExecutor { - } diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java index 2e2e756..47d7957 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java @@ -7,23 +7,75 @@ import org.springframework.data.jpa.domain.Specification; import uk.gov.laa.ccms.data.entity.Notification; +/** + * A utility class for creating specifications to filter and query notifications. + * + *

The {@link NotificationSpecification} class provides mechanisms to construct dynamic + * query criteria using the JPA Specification API. It allows filtering of + * {@link Notification} entities based on various attributes such as case reference number, + * provider case reference, assigned user, client surname, and more.

+ * + *

The filters include:

+ *
    + *
  • Case reference number (partial matching support).
  • + *
  • Provider case reference (partial matching support).
  • + *
  • Assigned user ID.
  • + *
  • Client surname (partial matching support).
  • + *
  • Fee earner ID.
  • + *
  • Should include closed notifications.
  • + *
  • Notification type.
  • + *
  • Date range (start and end dates).
  • + *
+ * + *

This allows querying for notifications based on multiple combinations of these filters, + * with all specified conditions combined.

+ * + * @see Notification + * @see Specification + * @see uk.gov.laa.ccms.data.repository.NotificationRepository + * @author Jamie Briggs + */ public class NotificationSpecification { + /** + * Private constructor to prevent instantiation of the NotificationSpecification class. + */ + private NotificationSpecification() {} + + /** + * Builds a {@link Specification} for filtering {@link Notification} entities based + * on various criteria. The method dynamically constructs filter + * conditions for the provided filter parameters. + * + * @param caseReferenceNumber the case reference number to filter by (optional). + * @param providerCaseReference the provider case reference to filter by (optional). + * @param assignedToUserId the user ID assigned to the notification (optional). + * @param clientSurname the client's surname to filter by (optional). + * @param feeEarnerId the ID of the fee earner to filter by (optional). + * @param includeClosed a flag to include closed notifications in the result set. + * @param notificationType the type of notification to filter by (optional). + * @param dateFrom the starting date for filtering notifications by the date assigned (inclusive). + * @param dateTo the ending date for filtering notifications by the date assigned (inclusive). + * @return a {@link Specification} object encapsulating the + * filtering logic for {@link Notification} entities. + */ public static Specification withFilters( String caseReferenceNumber, String providerCaseReference, String assignedToUserId, String clientSurname, Integer feeEarnerId, boolean includeClosed, String notificationType, LocalDate dateFrom, LocalDate dateTo - ){ + ) { return (root, query, criteriaBuilder) -> { List predicates = new ArrayList<>(); // Add predicates for each filter only if they are non-null if (caseReferenceNumber != null) { - predicates.add(criteriaBuilder.like(root.get("lscCaseRefReference"), "%" + caseReferenceNumber + "%")); + predicates.add(criteriaBuilder.like(root.get("lscCaseRefReference"), + "%" + caseReferenceNumber + "%")); } if (providerCaseReference != null) { - predicates.add(criteriaBuilder.like(root.get("providerCaseReference"), "%" + providerCaseReference + "%")); + predicates.add(criteriaBuilder.like(root.get("providerCaseReference"), + "%" + providerCaseReference + "%")); } if (assignedToUserId != null) { predicates.add(criteriaBuilder.equal(root.get("assignedTo"), assignedToUserId)); diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java index c3d9c76..feb9c2a 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/service/NotificationService.java @@ -59,11 +59,19 @@ public Optional getUserNotificationSummary(String userId) { } /** - * Retrieves a paginated list of notifications assigned to a specific user. + * Retrieves a paginated list of notifications. * - * @param pageable the pagination and sorting information for retrieving notifications - * @return an Optional containing a Notifications object if - * notifications are found, or an empty Optional otherwise + * @param caseReferenceNumber the case reference number to filter by (optional). + * @param providerCaseReference the provider case reference to filter by (optional). + * @param assignedToUserId the user ID assigned to the notification (optional). + * @param clientSurname the client's surname to filter by (optional). + * @param feeEarnerId the ID of the fee earner to filter by (optional). + * @param includeClosed a flag to include closed notifications in the result set. + * @param notificationType the type of notification to filter by (optional). + * @param dateFrom the starting date for filtering notifications by the date assigned (inclusive). + * @param dateTo the ending date for filtering notifications by the date assigned (inclusive). + * @param pageable the pageable to describe the requested pagination format. + * @return a paginated list of notifications. */ public Optional getNotifications(String caseReferenceNumber, String providerCaseReference, String assignedToUserId, String clientSurname, @@ -80,7 +88,6 @@ public Optional getNotifications(String caseReferenceNumber, dateFrom, dateTo), pageable); - //Page byAll = notificationRepository.findAll(Pageable.ofSize(100)); Notifications notifications = notificationsMapper.mapToNotificationsList(byAssignedTo); return Optional.ofNullable(notifications); } diff --git a/data-service/src/test/java/uk/gov/laa/ccms/data/service/NotificationServiceTest.java b/data-service/src/test/java/uk/gov/laa/ccms/data/service/NotificationServiceTest.java new file mode 100644 index 0000000..53dcc80 --- /dev/null +++ b/data-service/src/test/java/uk/gov/laa/ccms/data/service/NotificationServiceTest.java @@ -0,0 +1,130 @@ +package uk.gov.laa.ccms.data.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import uk.gov.laa.ccms.data.entity.Notification; +import uk.gov.laa.ccms.data.entity.NotificationCount; +import uk.gov.laa.ccms.data.mapper.NotificationSummaryMapper; +import uk.gov.laa.ccms.data.mapper.NotificationsMapper; +import uk.gov.laa.ccms.data.model.NotificationSummary; +import uk.gov.laa.ccms.data.model.Notifications; +import uk.gov.laa.ccms.data.model.UserDetail; +import uk.gov.laa.ccms.data.repository.NotificationCountRepository; +import uk.gov.laa.ccms.data.repository.NotificationRepository; + +@ExtendWith(MockitoExtension.class) +@DisplayName("Notification service test") +class NotificationServiceTest { + + private NotificationService notificationService; + @Mock + private NotificationCountRepository notificationCountRepository; + @Mock + private NotificationSummaryMapper notificationSummaryMapper; + @Mock + private NotificationRepository notificationRepository; + @Mock + private NotificationsMapper notificationsMapper; + @Mock + private UserService userService; + + + @BeforeEach + void setup() { + notificationService = new NotificationService(notificationCountRepository, + notificationSummaryMapper, notificationRepository, notificationsMapper, userService); + } + + @Test + @DisplayName("getUserNotificationSummary(): Returns notification summary") + void getUserNotificationSummary_returnsNotificationSummary() { + // Given + String userId = "123456"; + when(userService.getUser(userId)).thenReturn(Optional.of(new UserDetail())); + List notificationCounts = List.of(new NotificationCount()); + when(notificationCountRepository.findAllByIdUserLoginId(userId)).thenReturn(notificationCounts); + NotificationSummary expected = new NotificationSummary(); + when(notificationSummaryMapper.toNotificationSummary(notificationCounts)).thenReturn(expected); + // When + Optional userNotificationSummary = notificationService.getUserNotificationSummary( + userId); + // Then + assertEquals(expected, userNotificationSummary.get()); + } + + @Test + @DisplayName("getUserNotificationSummary(): User not found") + void getUserNotificationSummary_userNotFound() { + // Given + String userId = "123456"; + // When + Optional userNotificationSummary = notificationService.getUserNotificationSummary( + userId); + // Then + assertFalse(userNotificationSummary.isPresent()); + } + + @Test + @DisplayName("getNotifications(): Returns data") + void getNotifications_returnsData() { + // Given + PageImpl repositoryResult = new PageImpl<>(Collections.singletonList(new Notification())); + when(notificationRepository.findAll(any(Specification.class), any(Pageable.class))) + .thenReturn( + repositoryResult); + Notifications expected = new Notifications().size(1); + when(notificationsMapper.mapToNotificationsList(repositoryResult)).thenReturn( + expected + ); + // When + Optional result = notificationService.getNotifications( + "Case Ref", + "Prov case ref", + "Assigned user id", + "surname", + 123, + true, + "type", + LocalDate.of(2000, 1, 1), + LocalDate.of(2024, 1 ,1), Pageable.unpaged()); + // Then + assertTrue(result.isPresent()); + assertEquals(expected, result.get()); + } + + @Test + @DisplayName("getNotifications(): No data found") + void getNotifications_noDataFound() { + // Given + // When + Optional result = notificationService.getNotifications( + "Case Ref", + "Prov case ref", + "Assigned user id", + "surname", + 123, + true, + "type", + LocalDate.of(2000, 1, 1), + LocalDate.of(2024, 1 ,1), Pageable.unpaged()); + // Then + assertFalse(result.isPresent()); + } +} \ No newline at end of file From 2090584f4ec754d0237ed0505debd4ea6e833505 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Thu, 19 Dec 2024 16:44:28 +0000 Subject: [PATCH 13/15] Fix issue with NotificationSpecification Signed-off-by: Jamie Briggs --- .../repository/specification/NotificationSpecification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java index 47d7957..65c4d4d 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java @@ -87,7 +87,7 @@ public static Specification withFilters( predicates.add(criteriaBuilder.equal(root.get("feeEarnerPartyId"), feeEarnerId)); } if (!includeClosed) { - predicates.add(criteriaBuilder.isTrue(root.get("isOpen"))); + predicates.add(criteriaBuilder.equal(root.get("isOpen"), "true")); } if (notificationType != null) { predicates.add(criteriaBuilder.equal(root.get("actionNotificationInd"), notificationType)); From ccd49bf04ccfa04628db794dbca9e509d08ce1a6 Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Thu, 19 Dec 2024 16:49:27 +0000 Subject: [PATCH 14/15] Fix to test Signed-off-by: Jamie Briggs --- .../data/repository/NotificationRepositoryIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java b/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java index 3e17e14..31fdf0e 100644 --- a/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java +++ b/data-service/src/integrationTest/java/uk/gov/laa/ccms/data/repository/NotificationRepositoryIntegrationTest.java @@ -264,7 +264,7 @@ void shouldFilterByNotificationType(){ null, null, null, - false, "N", + true, "N", null, null); // When From 398d49f9e3041ded56051352f68b6db0c3416e5d Mon Sep 17 00:00:00 2001 From: Jamie Briggs Date: Fri, 20 Dec 2024 16:55:58 +0000 Subject: [PATCH 15/15] CCMSPUI-454: Stop filtering when param is empty string Signed-off-by: Jamie Briggs --- .../specification/NotificationSpecification.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java index 65c4d4d..1d7fc07 100644 --- a/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java +++ b/data-service/src/main/java/uk/gov/laa/ccms/data/repository/specification/NotificationSpecification.java @@ -69,18 +69,18 @@ public static Specification withFilters( List predicates = new ArrayList<>(); // Add predicates for each filter only if they are non-null - if (caseReferenceNumber != null) { + if (caseReferenceNumber != null && !caseReferenceNumber.isBlank()) { predicates.add(criteriaBuilder.like(root.get("lscCaseRefReference"), "%" + caseReferenceNumber + "%")); } - if (providerCaseReference != null) { + if (providerCaseReference != null && !providerCaseReference.isBlank()) { predicates.add(criteriaBuilder.like(root.get("providerCaseReference"), "%" + providerCaseReference + "%")); } - if (assignedToUserId != null) { + if (assignedToUserId != null && !assignedToUserId.isBlank()) { predicates.add(criteriaBuilder.equal(root.get("assignedTo"), assignedToUserId)); } - if (clientSurname != null) { + if (clientSurname != null && !clientSurname.isBlank()) { predicates.add(criteriaBuilder.like(root.get("personLastName"), "%" + clientSurname + "%")); } if (feeEarnerId != null) { @@ -89,7 +89,7 @@ public static Specification withFilters( if (!includeClosed) { predicates.add(criteriaBuilder.equal(root.get("isOpen"), "true")); } - if (notificationType != null) { + if (notificationType != null && !notificationType.isBlank()) { predicates.add(criteriaBuilder.equal(root.get("actionNotificationInd"), notificationType)); } if (dateFrom != null) {