diff --git a/postman/Prevention.postman_collection.json b/postman/Prevention.postman_collection.json index be7c67b60..878baef09 100644 --- a/postman/Prevention.postman_collection.json +++ b/postman/Prevention.postman_collection.json @@ -209,7 +209,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"projectGuid\": \"{{projectGuid}}\",\n \"activityCategoryCode\": \"TACT_PLAN\",\n \"fiscalYear\": 2023,\n \"projectPlanStatusCode\": \"ACTIVE\",\n \"planFiscalStatusCode\": \"DRAFT\",\n \"projectFiscalName\": \"Fiscal Project 1\",\n \"projectFiscalDescription\": \"This is a test project fiscal description.\",\n \"businessAreaComment\": \"Test comment\",\n \"estimatedClwrrAllocAmount\": 1000.00,\n \"fiscalAncillaryFundAmount\": 300.00,\n \"fiscalPlannedProjectSizeHa\": 10.5,\n \"fiscalPlannedCostPerHaAmt\": 500.00,\n \"fiscalReportedSpendAmount\": 0.00,\n \"fiscalActualAmount\": 0.00,\n \"fiscalCompletedSizeHa\": 0.0,\n \"fiscalActualCostPerHaAmt\": 0.0,\n \"firstNationsDelivPartInd\": true,\n \"firstNationsEngagementInd\": false,\n \"firstNationsPartner\": \"Test Partner\",\n \"resultsNumber\": \"RN123456\",\n \"resultsOpeningId\": \"RO12345\",\n \"resultsContactEmail\": \"contact@example.com\",\n \"submittedByName\": \"Test User\",\n \"submittedByUserGuid\": \"123e4567-e89\",\n \"submittedByUserUserid\": \"testuser\",\n \"submissionTimestamp\": \"2024-01-01T12:00:00Z\",\n \"isApprovedInd\": true,\n \"isDelayedInd\": false,\n \"fiscalForecastAmount\": 1800.00}", + "raw": "{\n \"projectGuid\": \"{{projectGuid}}\",\n \"activityCategoryCode\": \"TACT_PLAN\",\n \"fiscalYear\": 2023,\n \"projectPlanStatusCode\": \"ACTIVE\",\n \"planFiscalStatusCode\": \"DRAFT\",\n \"projectFiscalName\": \"Fiscal Project 1\",\n \"projectFiscalDescription\": \"This is a test project fiscal description.\",\n \"businessAreaComment\": \"Test comment\",\n \"estimatedClwrrAllocAmount\": 1000.00,\n \"fiscalAncillaryFundAmount\": 300.00,\n \"fiscalPlannedProjectSizeHa\": 10.5,\n \"fiscalPlannedCostPerHaAmt\": 500.00,\n \"fiscalReportedSpendAmount\": 0.00,\n \"fiscalActualAmount\": 0.00,\n \"fiscalCompletedSizeHa\": 0.0,\n \"fiscalActualCostPerHaAmt\": 0.0,\n \"firstNationsDelivPartInd\": true,\n \"firstNationsEngagementInd\": false,\n \"firstNationsPartner\": \"Test Partner\",\n \"resultsNumber\": \"RN123456\",\n \"resultsOpeningId\": \"RO12345\",\n \"resultsContactEmail\": \"contact@example.com\",\n \"submittedByName\": \"Test User\",\n \"submittedByUserGuid\": \"123e4567-e89\",\n \"submittedByUserUserid\": \"testuser\",\n \"submissionTimestamp\": \"2024-01-01T12:00:00Z\",\n \"isApprovedInd\": true,\n \"isDelayedInd\": false,\n \"fiscalForecastAmount\": 1800.00,\n \"ancillaryFundingSourceGuid\": \"2f84b1d7-4d84-432f-922c-e489fe7d764f\" \n}", "options": { "raw": { "language": "json" @@ -347,7 +347,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"projectPlanFiscalGuid\": \"{{projectPlanFiscalGuid}}\",\n \"projectGuid\": \"{{projectGuid}}\",\n \"activityCategoryCode\": \"RX_DEV\",\n \"fiscalYear\": 2024,\n \"projectPlanStatusCode\": \"ACTIVE\",\n \"planFiscalStatusCode\": \"PROPOSED\",\n \"projectFiscalName\": \"Fiscal Project 1\",\n \"projectFiscalDescription\": \"This is a test project fiscal description.\",\n \"businessAreaComment\": \"Test comment\",\n \"estimatedClwrrAllocAmount\": 1000.00,\n \"fiscalForecastAmount\": 300.00,\n \"fiscalAncillaryFundAmount\": 300.00,\n \"fiscalPlannedProjectSizeHa\": 10.5,\n \"fiscalPlannedCostPerHaAmt\": 500.00,\n \"fiscalReportedSpendAmount\": 0.00,\n \"fiscalActualAmount\": 0.00,\n \"fiscalCompletedSizeHa\": 0.0,\n \"fiscalActualCostPerHaAmt\": 0.0,\n \"firstNationsDelivPartInd\": true,\n \"firstNationsEngagementInd\": false,\n \"firstNationsPartner\": \"Test Partner\",\n \"resultsNumber\": \"RN123456\",\n \"resultsOpeningId\": \"RO12345\",\n \"resultsContactEmail\": \"contact@example.com\",\n \"submittedByName\": \"Test User\",\n \"submittedByUserGuid\": \"123e4567-e89\",\n \"submittedByUserUserid\": \"testuser\",\n \"submissionTimestamp\": \"2024-01-01T12:00:00Z\",\n \"isApprovedInd\": true,\n \"isDelayedInd\": false\n}", + "raw": "{\n \"projectPlanFiscalGuid\": \"{{projectPlanFiscalGuid}}\",\n \"projectGuid\": \"{{projectGuid}}\",\n \"activityCategoryCode\": \"RX_DEV\",\n \"fiscalYear\": 2024,\n \"projectPlanStatusCode\": \"ACTIVE\",\n \"planFiscalStatusCode\": \"PROPOSED\",\n \"projectFiscalName\": \"Fiscal Project 1\",\n \"projectFiscalDescription\": \"This is a test project fiscal description.\",\n \"businessAreaComment\": \"Test comment\",\n \"estimatedClwrrAllocAmount\": 1000.00,\n \"fiscalForecastAmount\": 300.00,\n \"fiscalAncillaryFundAmount\": 300.00,\n \"fiscalPlannedProjectSizeHa\": 10.5,\n \"fiscalPlannedCostPerHaAmt\": 500.00,\n \"fiscalReportedSpendAmount\": 0.00,\n \"fiscalActualAmount\": 0.00,\n \"fiscalCompletedSizeHa\": 0.0,\n \"fiscalActualCostPerHaAmt\": 0.0,\n \"firstNationsDelivPartInd\": true,\n \"firstNationsEngagementInd\": false,\n \"firstNationsPartner\": \"Test Partner\",\n \"resultsNumber\": \"RN123456\",\n \"resultsOpeningId\": \"RO12345\",\n \"resultsContactEmail\": \"contact@example.com\",\n \"submittedByName\": \"Test User\",\n \"submittedByUserGuid\": \"123e4567-e89\",\n \"submittedByUserUserid\": \"testuser\",\n \"submissionTimestamp\": \"2024-01-01T12:00:00Z\",\n \"isApprovedInd\": true,\n \"isDelayedInd\": false,\n \"ancillaryFundingSourceGuid\": \"483707b1-86f2-4d54-94f5-8cbf1aaef0c7\" \n}", "options": { "raw": { "language": "json" diff --git a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/controllers/ProjectFiscalController.java b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/controllers/ProjectFiscalController.java index 66fb5c7fa..356e8c3e3 100644 --- a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/controllers/ProjectFiscalController.java +++ b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/controllers/ProjectFiscalController.java @@ -57,12 +57,15 @@ public ProjectFiscalController(ProjectFiscalService projectFiscalService) { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CollectionModel.class))), @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(schema = @Schema(implementation = MessageListRsrc.class))), @ApiResponse(responseCode = "403", description = "Forbidden"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "409", description = "Conflict"), @ApiResponse(responseCode = "412", description = "Precondition Failed"), @ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(schema = @Schema(implementation = MessageListRsrc.class)))}) @Parameter(name = HeaderConstants.VERSION_HEADER, description = HeaderConstants.VERSION_HEADER_DESCRIPTION, required = false, schema = @Schema(implementation = Integer.class), in = ParameterIn.HEADER) @Parameter(name = HeaderConstants.IF_MATCH_HEADER, description = HeaderConstants.IF_MATCH_DESCRIPTION, required = true, schema = @Schema(implementation = String.class), in = ParameterIn.HEADER) - public ResponseEntity> getAllProjectFiscals() { + public ResponseEntity> getAllProjectFiscals(@PathVariable("projectId") String projectId) { log.debug(" >> getAllProjectFiscals"); ResponseEntity> response; try { - response = ok(projectFiscalService.getAllProjectFiscals()); + response = ok(projectFiscalService.getAllProjectFiscals(projectId)); + } catch (ServiceException e) { + response = internalServerError(); + log.error(" ### ServiceException while fetching Project Fiscals", e); } catch (RuntimeException e) { response = internalServerError(); log.error(" ### Error while fetching Project Fiscals", e); diff --git a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/assemblers/ProjectFiscalResourceAssembler.java b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/assemblers/ProjectFiscalResourceAssembler.java index e5b9d0cc9..938b8b3a6 100644 --- a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/assemblers/ProjectFiscalResourceAssembler.java +++ b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/assemblers/ProjectFiscalResourceAssembler.java @@ -36,11 +36,11 @@ public ProjectFiscalModel toModel(final ProjectFiscalEntity entity) { model.setProjectGuid(entity.getProject() != null && entity.getProject().getProjectGuid() != null ? entity.getProject().getProjectGuid().toString() : null); + model.setAncillaryFundingSourceGuid(entity.getAncillaryFundingSourceGuid() != null ? + entity.getAncillaryFundingSourceGuid().toString() : null); model.setActivityCategoryCode(entity.getActivityCategoryCode()); model.setFiscalYear(entity.getFiscalYear() != null ? entity.getFiscalYear().longValue() : null); - model.setAncillaryFundingSourceGuid(entity.getAncillaryFundingSourceGuid() != null - ? entity.getAncillaryFundingSourceGuid().getAncillaryFundingSourceGuid().toString() - : null); + model.setAncillaryFundingSourceGuid(String.valueOf(entity.getAncillaryFundingSourceGuid())); model.setProjectPlanStatusCode(entity.getProjectPlanStatusCode()); model.setPlanFiscalStatusCode(entity.getPlanFiscalStatusCode()); model.setEndorsementCode(entity.getEndorsementCode()); @@ -117,6 +117,9 @@ public ProjectFiscalEntity toEntity(ProjectFiscalModel model, ProjectEntity proj entity.setFiscalYear(model.getFiscalYear() != null ? BigDecimal.valueOf(model.getFiscalYear()) : null); + if (model.getAncillaryFundingSourceGuid() != null) { + entity.setAncillaryFundingSourceGuid(UUID.fromString(model.getAncillaryFundingSourceGuid())); + } entity.setProjectPlanStatusCode(model.getProjectPlanStatusCode()); entity.setPlanFiscalStatusCode(model.getPlanFiscalStatusCode()); entity.setEndorsementCode(model.getEndorsementCode()); @@ -180,6 +183,10 @@ public ProjectFiscalEntity updateEntity(ProjectFiscalModel projectFiscalModel, P projectFiscalModel.getFiscalYear() != null ? BigDecimal.valueOf(projectFiscalModel.getFiscalYear()) : existingEntity.getFiscalYear()); + existingEntity.setAncillaryFundingSourceGuid(nonNullOrDefault( + projectFiscalModel.getAncillaryFundingSourceGuid() != null ? UUID.fromString(projectFiscalModel.getAncillaryFundingSourceGuid()) : null, + existingEntity.getAncillaryFundingSourceGuid() + )); existingEntity.setProjectPlanStatusCode( nonNullOrDefault(projectFiscalModel.getProjectPlanStatusCode(), existingEntity.getProjectPlanStatusCode())); existingEntity.setPlanFiscalStatusCode( diff --git a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/entities/ProjectFiscalEntity.java b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/entities/ProjectFiscalEntity.java index 4699abbf4..110ca10f5 100644 --- a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/entities/ProjectFiscalEntity.java +++ b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/entities/ProjectFiscalEntity.java @@ -46,9 +46,8 @@ public class ProjectFiscalEntity implements Serializable { @Column(name = "fiscal_year", precision = 4) private BigDecimal fiscalYear; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "ancillary_funding_source_guid", referencedColumnName = "ancillary_funding_source_guid") - private AncillaryFundingSourceCodeEntity ancillaryFundingSourceGuid; + @Column(name = "ancillary_funding_source_guid", columnDefinition = "uuid") + private UUID ancillaryFundingSourceGuid; @NotNull @Column(name = "project_plan_status_code", length = 10) diff --git a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/repositories/ProjectFiscalRepository.java b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/repositories/ProjectFiscalRepository.java index fe9957602..35cae4c21 100644 --- a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/repositories/ProjectFiscalRepository.java +++ b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/data/repositories/ProjectFiscalRepository.java @@ -4,8 +4,10 @@ import ca.bc.gov.nrs.wfprev.data.entities.ProjectFiscalEntity; import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import java.util.List; import java.util.UUID; @RepositoryRestResource(exported = false) public interface ProjectFiscalRepository extends CommonRepository { + List findAllByProject_ProjectGuid(UUID projectGuid); } diff --git a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalService.java b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalService.java index b6ab3ee87..6a2986717 100644 --- a/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalService.java +++ b/server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalService.java @@ -38,9 +38,10 @@ public ProjectFiscalService(ProjectFiscalRepository projectFiscalRepository, Pro this.projectResourceAssembler = projectResourceAssembler; } - public CollectionModel getAllProjectFiscals() throws ServiceException { - List all = projectFiscalRepository.findAll(); - return projectFiscalResourceAssembler.toCollectionModel(all); + public CollectionModel getAllProjectFiscals(String projectId) throws ServiceException { + UUID projectGuid = UUID.fromString(projectId); + List projectFiscals = projectFiscalRepository.findAllByProject_ProjectGuid(projectGuid); + return projectFiscalResourceAssembler.toCollectionModel(projectFiscals); } public ProjectFiscalModel createProjectFiscal(ProjectFiscalModel projectFiscalModel) { diff --git a/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/ProjectFiscalControllerTest.java b/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/ProjectFiscalControllerTest.java index ccb62c601..d9c3f5d4f 100644 --- a/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/ProjectFiscalControllerTest.java +++ b/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/ProjectFiscalControllerTest.java @@ -149,11 +149,12 @@ void testUpdateProjectFiscal_NotFound() throws Exception { @Test @WithMockUser void testGetAllProjectFiscals_Success() throws Exception { + String projectGuid = "123e4567-e89b-12d3-a456-426614174001"; // GIVEN a list of ProjectFiscalModel List projectFiscalModels = List.of( ProjectFiscalModel.builder() .projectPlanFiscalGuid("123e4567-e89b-12d3-a456-426614174000") - .projectGuid("123e4567-e89b-12d3-a456-426614174001") + .projectGuid(projectGuid) .activityCategoryCode("Tactical Planning") .fiscalYear(2024L) .submissionTimestamp(new Date(1672531200000L)) @@ -167,7 +168,7 @@ void testGetAllProjectFiscals_Success() throws Exception { .build() ); - when(projectFiscalService.getAllProjectFiscals()).thenReturn(CollectionModel.of(projectFiscalModels)); + when(projectFiscalService.getAllProjectFiscals(projectGuid)).thenReturn(CollectionModel.of(projectFiscalModels)); // WHEN we call the getAllProjectFiscals method mockMvc.perform(get("/projects/123e4567-e89b-12d3-a456-426614174001/projectFiscals") @@ -202,20 +203,25 @@ void testGetAllProjectFiscals_Success() throws Exception { @WithMockUser void testGetAllProjectFiscals_ServiceException() throws Exception { // GIVEN the service throws a ServiceException - when(projectFiscalService.getAllProjectFiscals()).thenThrow(new ServiceException("Test ServiceException")); + when(projectFiscalService.getAllProjectFiscals(anyString())) + .thenThrow(new ServiceException("Test ServiceException")); + // WHEN we call the getAllProjectFiscals method mockMvc.perform(get("/projects/1234/projectFiscals") .contentType(MediaType.APPLICATION_JSON)) // THEN we expect a 500 Internal Server Error .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$").doesNotExist()); // Ensure no body is returned + + // Verify if the service was called + verify(projectFiscalService).getAllProjectFiscals("1234"); } @Test @WithMockUser void testGetAllProjectFiscals_Empty() throws Exception { // GIVEN an empty list from the service - when(projectFiscalService.getAllProjectFiscals()).thenReturn(CollectionModel.of(Collections.emptyList())); + when(projectFiscalService.getAllProjectFiscals("123e4567-e89b-12d3-a456-426614174001")).thenReturn(CollectionModel.of(Collections.emptyList())); // WHEN we call the getAllProjectFiscals method mockMvc.perform(get("/projects/1234/projectFiscals") @@ -230,7 +236,8 @@ void testGetAllProjectFiscals_Empty() throws Exception { @WithMockUser void testGetAllProjectFiscals_UnexpectedException() throws Exception { // GIVEN the service throws a RuntimeException - when(projectFiscalService.getAllProjectFiscals()).thenThrow(new RuntimeException("Unexpected error")); + when(projectFiscalService.getAllProjectFiscals(anyString())) + .thenThrow(new RuntimeException("Unexpected error")); // WHEN we call the getAllProjectFiscals method mockMvc.perform(get("/projects/1234/projectFiscals") @@ -238,6 +245,9 @@ void testGetAllProjectFiscals_UnexpectedException() throws Exception { // THEN we expect a 500 Internal Server Error .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$").doesNotExist()); // Ensure no body is returned + + // Verify the service was called + verify(projectFiscalService).getAllProjectFiscals("1234"); } @Test diff --git a/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalServiceTest.java b/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalServiceTest.java index 2e5ae95c6..c98e985f2 100644 --- a/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalServiceTest.java +++ b/server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/services/ProjectFiscalServiceTest.java @@ -47,10 +47,18 @@ void setup() { @Test void testGetAllProjectFiscals_Empty() { // GIVEN I have no project fiscals - when(projectFiscalRepository.findAll()).thenReturn(Collections.emptyList()); - when(projectFiscalResourceAssembler.toCollectionModel(Collections.emptyList())).thenReturn(CollectionModel.of(Collections.emptyList())); + UUID projectGuid = UUID.fromString("123e4567-e89b-12d3-a456-426614174001"); + + // Update the mock to use the new repository method + when(projectFiscalRepository.findAllByProject_ProjectGuid(projectGuid)) + .thenReturn(Collections.emptyList()); + when(projectFiscalResourceAssembler.toCollectionModel(Collections.emptyList())) + .thenReturn(CollectionModel.of(Collections.emptyList())); + // WHEN I get all project fiscals - CollectionModel allProjectFiscals = projectFiscalService.getAllProjectFiscals(); + CollectionModel allProjectFiscals = + projectFiscalService.getAllProjectFiscals(projectGuid.toString()); + // THEN I should get an empty list assertEquals(0, allProjectFiscals.getContent().size()); } @@ -190,11 +198,17 @@ void testGetAllProjectFiscals_NotEmpty() { .build() ); - when(projectFiscalRepository.findAll()).thenReturn(entities); - when(projectFiscalResourceAssembler.toCollectionModel(entities)).thenReturn(CollectionModel.of(Arrays.asList(projectFiscalModel1, projectFiscalModel2))); + UUID projectGuid = UUID.fromString("123e4567-e89b-12d3-a456-426614174001"); + + // Update the mock to use the new repository method + when(projectFiscalRepository.findAllByProject_ProjectGuid(projectGuid)) + .thenReturn(entities); + when(projectFiscalResourceAssembler.toCollectionModel(entities)) + .thenReturn(CollectionModel.of(Arrays.asList(projectFiscalModel1, projectFiscalModel2))); // WHEN I get all project fiscals - CollectionModel allProjectFiscals = projectFiscalService.getAllProjectFiscals(); + CollectionModel allProjectFiscals = + projectFiscalService.getAllProjectFiscals(projectGuid.toString()); // THEN I should get a list with some elements Assertions.assertNotEquals(0, allProjectFiscals.getContent().size());