Skip to content

Commit d7db742

Browse files
authored
WFPREV-437 Update spatial added badge when spatial file is added to activity (#790)
1 parent d2e644e commit d7db742

File tree

3 files changed

+186
-9
lines changed

3 files changed

+186
-9
lines changed

client/wfprev-war/src/main/angular/src/app/components/edit-project/activities/activities.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CommonModule } from '@angular/common';
2-
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
2+
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
33
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
44
import { MomentDateAdapter } from '@angular/material-moment-adapter';
55
import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -57,7 +57,7 @@ export const CUSTOM_DATE_FORMATS = {
5757
],
5858
})
5959

60-
export class ActivitiesComponent implements OnChanges, OnInit, CanComponentDeactivate{
60+
export class ActivitiesComponent implements OnChanges, CanComponentDeactivate{
6161
@Input() fiscalGuid: string = '';
6262
@Output() boundariesUpdated = new EventEmitter<void>();
6363

@@ -90,8 +90,6 @@ export class ActivitiesComponent implements OnChanges, OnInit, CanComponentDeact
9090
public cd: ChangeDetectorRef
9191
) {}
9292

93-
ngOnInit(): void {
94-
}
9593
ngOnChanges(changes: SimpleChanges): void {
9694
if (changes['fiscalGuid'] && changes['fiscalGuid'].currentValue) {
9795
// Clear previous state before loading new fiscal data
@@ -779,5 +777,7 @@ export class ActivitiesComponent implements OnChanges, OnInit, CanComponentDeact
779777

780778
onFilesChanged() {
781779
this.boundariesUpdated.emit(); // Notify ProjectFiscalsComponent
780+
this.getActivities();
782781
}
782+
783783
}

server/wfprev-api/src/main/java/ca/bc/gov/nrs/wfprev/controllers/ActivityBoundaryController.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import ca.bc.gov.nrs.common.wfone.rest.resource.MessageListRsrc;
55
import ca.bc.gov.nrs.wfprev.common.controllers.CommonController;
66
import ca.bc.gov.nrs.wfprev.data.models.ActivityBoundaryModel;
7+
import ca.bc.gov.nrs.wfprev.data.models.ActivityModel;
78
import ca.bc.gov.nrs.wfprev.services.ActivityBoundaryService;
9+
import ca.bc.gov.nrs.wfprev.services.ActivityService;
810
import ca.bc.gov.nrs.wfprev.services.CoordinatesService;
911
import io.swagger.v3.oas.annotations.Operation;
1012
import io.swagger.v3.oas.annotations.Parameter;
@@ -37,13 +39,15 @@
3739
@Slf4j
3840
@RequestMapping(value = "/projects/{projectGuid}/projectFiscals/{projectPlanFiscalGuid}/activities/{activityGuid}/activityBoundary")
3941
public class ActivityBoundaryController extends CommonController {
42+
private final ActivityService activityService;
4043
private final ActivityBoundaryService activityBoundaryService;
4144
private final CoordinatesService coordinatesService;
4245

43-
public ActivityBoundaryController(ActivityBoundaryService activityBoundaryService, CoordinatesService coordinatesService) {
46+
public ActivityBoundaryController(ActivityBoundaryService activityBoundaryService, CoordinatesService coordinatesService, ActivityService activityService) {
4447
super(ActivityBoundaryController.class.getName());
4548
this.activityBoundaryService = activityBoundaryService;
4649
this.coordinatesService = coordinatesService;
50+
this.activityService = activityService;
4751
}
4852

4953
@GetMapping
@@ -142,6 +146,14 @@ public ResponseEntity<ActivityBoundaryModel> createActivityBoundary(
142146
projectGuid, projectPlanFiscalGuid, activityGuid, resource);
143147
coordinatesService.updateProjectCoordinates(projectGuid);
144148

149+
// Update activity spatial indicator
150+
ActivityModel activity = activityService.getActivity(projectGuid, projectPlanFiscalGuid, activityGuid);
151+
if(activity != null) {
152+
activity.setIsSpatialAddedInd(true);
153+
activityService.updateActivity(projectGuid, projectPlanFiscalGuid, activity);
154+
155+
}
156+
145157
return ResponseEntity.status(201).body(newResource);
146158
} catch (DataIntegrityViolationException e) {
147159
log.error(" ### DataIntegrityViolationException while creating Activity Boundary", e);
@@ -182,6 +194,13 @@ public ResponseEntity<ActivityBoundaryModel> updateActivityBoundary(
182194
projectGuid, projectPlanFiscalGuid, activityGuid, resource);
183195
coordinatesService.updateProjectCoordinates(projectGuid);
184196

197+
// Update activity spatial indicator
198+
ActivityModel activity = activityService.getActivity(projectGuid, projectPlanFiscalGuid, activityGuid);
199+
if (activity != null) {
200+
activity.setIsSpatialAddedInd(true);
201+
activityService.updateActivity(projectGuid, projectPlanFiscalGuid, activity);
202+
}
203+
185204
return updatedResource == null ? notFound() : ok(updatedResource);
186205
} catch (DataIntegrityViolationException e) {
187206
log.error(" ### DataIntegrityViolationException while updating Activity Boundary", e);
@@ -219,6 +238,15 @@ public ResponseEntity<Void> deleteActivityBoundary(
219238
try {
220239
activityBoundaryService.deleteActivityBoundary(projectGuid, projectPlanFiscalGuid, activityGuid, id);
221240
coordinatesService.updateProjectCoordinates(projectGuid);
241+
242+
// Update activity spatial indicator
243+
ActivityModel activity = activityService.getActivity(projectGuid, projectPlanFiscalGuid, activityGuid);
244+
if(activity != null) {
245+
CollectionModel<ActivityBoundaryModel> boundaries = activityBoundaryService.getAllActivityBoundaries(projectGuid, projectPlanFiscalGuid, activityGuid);
246+
activity.setIsSpatialAddedInd(!boundaries.getContent().isEmpty());
247+
activityService.updateActivity(projectGuid, projectPlanFiscalGuid, activity);
248+
}
249+
222250
return ResponseEntity.noContent().build();
223251
} catch (EntityNotFoundException e) {
224252
log.warn(" ### Activity Boundary for deletion not found: {}", id, e);

server/wfprev-api/src/test/java/ca/bc/gov/nrs/wfprev/ActivityBoundaryControllerTest.java

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import ca.bc.gov.nrs.wfprev.controllers.ActivityBoundaryController;
44
import ca.bc.gov.nrs.wfprev.data.models.ActivityBoundaryModel;
5+
import ca.bc.gov.nrs.wfprev.data.models.ActivityModel;
56
import ca.bc.gov.nrs.wfprev.services.ActivityBoundaryService;
7+
import ca.bc.gov.nrs.wfprev.services.ActivityService;
68
import ca.bc.gov.nrs.wfprev.services.CoordinatesService;
79
import com.nimbusds.jose.shaded.gson.Gson;
810
import com.nimbusds.jose.shaded.gson.GsonBuilder;
@@ -17,6 +19,7 @@
1719
import org.locationtech.jts.geom.LinearRing;
1820
import org.locationtech.jts.geom.MultiPolygon;
1921
import org.locationtech.jts.geom.Polygon;
22+
import org.mockito.ArgumentCaptor;
2023
import org.springframework.beans.factory.annotation.Autowired;
2124
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
2225
import org.springframework.boot.test.mock.mockito.MockBean;
@@ -35,12 +38,16 @@
3538
import java.util.List;
3639
import java.util.UUID;
3740

41+
import static org.junit.jupiter.api.Assertions.assertFalse;
42+
import static org.junit.jupiter.api.Assertions.assertTrue;
3843
import static org.mockito.ArgumentMatchers.any;
3944
import static org.mockito.ArgumentMatchers.anyString;
45+
import static org.mockito.ArgumentMatchers.argThat;
4046
import static org.mockito.ArgumentMatchers.eq;
4147
import static org.mockito.Mockito.doNothing;
4248
import static org.mockito.Mockito.verify;
4349
import static org.mockito.Mockito.when;
50+
import static org.mockito.Mockito.never;
4451
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
4552
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
4653
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -59,6 +66,9 @@ class ActivityBoundaryControllerTest {
5966
@MockBean
6067
private CoordinatesService coordinatesService;
6168

69+
@MockBean
70+
private ActivityService activityService;
71+
6272
@Autowired
6373
private MockMvc mockMvc;
6474

@@ -200,10 +210,15 @@ void testGetActivityBoundary_EntityNotFoundException() throws Exception {
200210
@WithMockUser
201211
void testCreateActivityBoundary_Success() throws Exception {
202212
ActivityBoundaryModel requestModel = buildActivityBoundaryRequestModel();
213+
ActivityModel activity = new ActivityModel();
214+
activity.setActivityGuid(requestModel.getActivityGuid());
203215

204216
when(activityBoundaryService.createActivityBoundary(anyString(), anyString(), anyString(), any(ActivityBoundaryModel.class)))
205217
.thenReturn(requestModel);
206218

219+
when(activityService.getActivity(anyString(), anyString(), anyString()))
220+
.thenReturn(activity);
221+
207222
String requestJson = activityBoundaryJson.formatted(
208223
requestModel.getActivityBoundaryGuid(),
209224
requestModel.getActivityGuid(),
@@ -218,8 +233,17 @@ void testCreateActivityBoundary_Success() throws Exception {
218233
.content(requestJson))
219234
.andExpect(status().isCreated())
220235
.andExpect(jsonPath("$.activityBoundaryGuid").value(requestModel.getActivityBoundaryGuid()));
221-
}
222236

237+
// Verify calls to activityService
238+
verify(activityService).getActivity(anyString(), anyString(), anyString());
239+
240+
verify(activityService).updateActivity(
241+
anyString(),
242+
anyString(),
243+
argThat(updatedActivity ->
244+
updatedActivity.getIsSpatialAddedInd() != null && updatedActivity.getIsSpatialAddedInd())
245+
);
246+
}
223247
@Test
224248
@WithMockUser
225249
void testCreateActivityBoundary_DataIntegrityViolationException() throws Exception {
@@ -243,6 +267,35 @@ void testCreateActivityBoundary_DataIntegrityViolationException() throws Excepti
243267
.andExpect(status().isBadRequest());
244268
}
245269

270+
@Test
271+
@WithMockUser
272+
void testCreateActivityBoundary_NoActivityFound() throws Exception {
273+
ActivityBoundaryModel requestModel = buildActivityBoundaryRequestModel();
274+
275+
when(activityBoundaryService.createActivityBoundary(anyString(), anyString(), anyString(), any(ActivityBoundaryModel.class)))
276+
.thenReturn(requestModel);
277+
278+
when(activityService.getActivity(anyString(), anyString(), anyString()))
279+
.thenReturn(null);
280+
281+
String requestJson = activityBoundaryJson.formatted(
282+
requestModel.getActivityBoundaryGuid(),
283+
requestModel.getActivityGuid(),
284+
requestModel.getSystemStartTimestamp().getTime(),
285+
requestModel.getSystemEndTimestamp().getTime() + 1000,
286+
requestModel.getCollectionDate().getTime()
287+
);
288+
289+
mockMvc.perform(post("/projects/{projectId}/projectFiscals/{projectFiscalId}/activities/{activityId}/activityBoundary",
290+
UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())
291+
.contentType(MediaType.APPLICATION_JSON)
292+
.content(requestJson))
293+
.andExpect(status().isCreated());
294+
295+
verify(activityService).getActivity(anyString(), anyString(), anyString());
296+
verify(activityService, org.mockito.Mockito.never()).updateActivity(anyString(), anyString(), any(ActivityModel.class));
297+
}
298+
246299
@Test
247300
@WithMockUser
248301
void testCreateActivityBoundary_Exception() throws Exception {
@@ -293,9 +346,14 @@ void testCreateActivityBoundary_IllegalArgumentException() throws Exception {
293346
@WithMockUser
294347
void testUpdateActivityBoundary_Success() throws Exception {
295348
ActivityBoundaryModel requestModel = buildActivityBoundaryRequestModel();
349+
ActivityModel activity = new ActivityModel();
350+
activity.setActivityGuid(requestModel.getActivityGuid());
351+
activity.setIsSpatialAddedInd(false);
296352

297353
when(activityBoundaryService.updateActivityBoundary(anyString(), anyString(), anyString(), any(ActivityBoundaryModel.class)))
298354
.thenReturn(requestModel);
355+
when(activityService.getActivity(anyString(), anyString(), anyString()))
356+
.thenReturn(activity);
299357

300358
String requestJson = activityBoundaryJson.formatted(
301359
requestModel.getActivityBoundaryGuid(),
@@ -311,6 +369,42 @@ void testUpdateActivityBoundary_Success() throws Exception {
311369
.content(requestJson))
312370
.andExpect(status().isOk())
313371
.andExpect(jsonPath("$.activityBoundaryGuid").value(requestModel.getActivityBoundaryGuid()));
372+
373+
// Verify spatial indicator update
374+
verify(activityService).getActivity(anyString(), anyString(), anyString());
375+
ArgumentCaptor<ActivityModel> activityCaptor = ArgumentCaptor.forClass(ActivityModel.class);
376+
verify(activityService).updateActivity(anyString(), anyString(), activityCaptor.capture());
377+
378+
assertTrue(activityCaptor.getValue().getIsSpatialAddedInd(), "isSpatialAddedInd should be true after update");
379+
}
380+
381+
@Test
382+
@WithMockUser
383+
void testUpdateActivityBoundary_NoActivityFound() throws Exception {
384+
ActivityBoundaryModel requestModel = buildActivityBoundaryRequestModel();
385+
386+
when(activityBoundaryService.updateActivityBoundary(anyString(), anyString(), anyString(), any(ActivityBoundaryModel.class)))
387+
.thenReturn(requestModel);
388+
389+
when(activityService.getActivity(anyString(), anyString(), anyString()))
390+
.thenReturn(null);
391+
392+
String requestJson = activityBoundaryJson.formatted(
393+
requestModel.getActivityBoundaryGuid(),
394+
requestModel.getActivityGuid(),
395+
requestModel.getSystemStartTimestamp().getTime(),
396+
requestModel.getSystemEndTimestamp().getTime() + 1000,
397+
requestModel.getCollectionDate().getTime()
398+
);
399+
400+
mockMvc.perform(put("/projects/{projectId}/projectFiscals/{projectFiscalId}/activities/{activityId}/activityBoundary/{id}",
401+
UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), requestModel.getActivityBoundaryGuid())
402+
.contentType(MediaType.APPLICATION_JSON)
403+
.content(requestJson))
404+
.andExpect(status().isOk());
405+
406+
verify(activityService).getActivity(anyString(), anyString(), anyString());
407+
verify(activityService, never()).updateActivity(anyString(), anyString(), any(ActivityModel.class));
314408
}
315409

316410
@Test
@@ -410,14 +504,69 @@ void testUpdateActivityBoundary_DataIntegrityViolationException() throws Excepti
410504
@WithMockUser
411505
void testDeleteActivityBoundary_Success() throws Exception {
412506
UUID boundaryId = UUID.randomUUID();
413-
doNothing().when(activityBoundaryService).deleteActivityBoundary(anyString(), anyString(), anyString(), anyString());
507+
UUID projectId = UUID.randomUUID();
508+
UUID fiscalId = UUID.randomUUID();
509+
UUID activityId = UUID.randomUUID();
510+
511+
ActivityModel updatedActivity = new ActivityModel();
512+
updatedActivity.setIsSpatialAddedInd(false);
513+
514+
when(activityService.updateActivity(eq(projectId.toString()), eq(fiscalId.toString()), any(ActivityModel.class)))
515+
.thenReturn(updatedActivity);
516+
517+
doNothing().when(activityBoundaryService).deleteActivityBoundary(
518+
eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()), eq(boundaryId.toString()));
519+
520+
when(activityService.getActivity(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString())))
521+
.thenReturn(new ActivityModel());
522+
523+
when(activityBoundaryService.getAllActivityBoundaries(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString())))
524+
.thenReturn(CollectionModel.empty());
525+
526+
doNothing().when(coordinatesService).updateProjectCoordinates(eq(projectId.toString()));
527+
528+
when(activityService.updateActivity(eq(projectId.toString()), eq(fiscalId.toString()), any(ActivityModel.class)))
529+
.thenReturn(updatedActivity);
530+
531+
mockMvc.perform(delete("/projects/{projectId}/projectFiscals/{projectFiscalId}/activities/{activityId}/activityBoundary/{id}",
532+
projectId, fiscalId, activityId, boundaryId)
533+
.header(HttpHeaders.AUTHORIZATION, "Bearer test-token"))
534+
.andExpect(status().isNoContent());
535+
536+
verify(activityBoundaryService).deleteActivityBoundary(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()), eq(boundaryId.toString()));
537+
verify(coordinatesService).updateProjectCoordinates(eq(projectId.toString()));
538+
verify(activityService).getActivity(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()));
539+
verify(activityBoundaryService).getAllActivityBoundaries(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()));
540+
541+
ArgumentCaptor<ActivityModel> activityCaptor = ArgumentCaptor.forClass(ActivityModel.class);
542+
verify(activityService).updateActivity(eq(projectId.toString()), eq(fiscalId.toString()), activityCaptor.capture());
543+
544+
assertFalse(activityCaptor.getValue().getIsSpatialAddedInd(), "isSpatialAddedInd should be false after deleting last boundary");
545+
}
546+
547+
@Test
548+
@WithMockUser
549+
void testDeleteActivityBoundary_NoActivityFound() throws Exception {
550+
UUID boundaryId = UUID.randomUUID();
551+
UUID projectId = UUID.randomUUID();
552+
UUID fiscalId = UUID.randomUUID();
553+
UUID activityId = UUID.randomUUID();
554+
555+
doNothing().when(activityBoundaryService).deleteActivityBoundary(
556+
eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()), eq(boundaryId.toString()));
557+
doNothing().when(coordinatesService).updateProjectCoordinates(eq(projectId.toString()));
558+
when(activityService.getActivity(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString())))
559+
.thenReturn(null);
414560

415561
mockMvc.perform(delete("/projects/{projectId}/projectFiscals/{projectFiscalId}/activities/{activityId}/activityBoundary/{id}",
416-
UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), boundaryId)
562+
projectId, fiscalId, activityId, boundaryId)
417563
.header(HttpHeaders.AUTHORIZATION, "Bearer test-token"))
418564
.andExpect(status().isNoContent());
419565

420-
verify(activityBoundaryService).deleteActivityBoundary(anyString(), anyString(), anyString(), eq(boundaryId.toString()));
566+
verify(activityBoundaryService).deleteActivityBoundary(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()), eq(boundaryId.toString()));
567+
verify(coordinatesService).updateProjectCoordinates(eq(projectId.toString()));
568+
verify(activityService).getActivity(eq(projectId.toString()), eq(fiscalId.toString()), eq(activityId.toString()));
569+
verify(activityService, org.mockito.Mockito.never()).updateActivity(anyString(), anyString(), any(ActivityModel.class));
421570
}
422571

423572
ActivityBoundaryModel buildActivityBoundaryRequestModel() {

0 commit comments

Comments
 (0)