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) {