From 58e3143b354588f45e50acad24a63b0ef75d77da Mon Sep 17 00:00:00 2001 From: Steven Grimm <1248649+sgrimm@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:53:30 -0700 Subject: [PATCH] SW-6204 Disallow replacement of 25m plots (#2552) When we switch to the 30m plot size, there may be existing observations in progress. They are able to finish as normal, but since we no longer support creating new 4-plot clusters, we can't support the "request monitoring plot replacement" feature for those observations since plot replacement can trigger creation of new permanent clusters. Add a check to reject attempts to replace plots with sizes different from the current size we use for new plots. In practice, this means replacing 25m plots will fail but replacing 30m plots will succeed. --- .../backend/tracking/ObservationService.kt | 10 ++++++++++ .../backend/tracking/db/Exceptions.kt | 7 +++++++ .../backend/tracking/ObservationServiceTest.kt | 14 ++++++++++++++ .../backend/tracking/PlotAssignmentTest.kt | 1 + 4 files changed, 32 insertions(+) diff --git a/src/main/kotlin/com/terraformation/backend/tracking/ObservationService.kt b/src/main/kotlin/com/terraformation/backend/tracking/ObservationService.kt index bd8db803d73b..696db688770f 100644 --- a/src/main/kotlin/com/terraformation/backend/tracking/ObservationService.kt +++ b/src/main/kotlin/com/terraformation/backend/tracking/ObservationService.kt @@ -10,6 +10,7 @@ import com.terraformation.backend.db.tracking.ObservationId import com.terraformation.backend.db.tracking.ObservationPlotPosition import com.terraformation.backend.db.tracking.ObservationState import com.terraformation.backend.db.tracking.PlantingSiteId +import com.terraformation.backend.db.tracking.tables.daos.MonitoringPlotsDao import com.terraformation.backend.db.tracking.tables.daos.ObservationPhotosDao import com.terraformation.backend.db.tracking.tables.pojos.ObservationPhotosRow import com.terraformation.backend.db.tracking.tables.references.OBSERVATION_PHOTOS @@ -28,6 +29,7 @@ import com.terraformation.backend.tracking.db.PlantingSiteStore import com.terraformation.backend.tracking.db.PlotAlreadyCompletedException import com.terraformation.backend.tracking.db.PlotNotFoundException import com.terraformation.backend.tracking.db.PlotNotInObservationException +import com.terraformation.backend.tracking.db.PlotSizeNotReplaceableException import com.terraformation.backend.tracking.db.ScheduleObservationWithoutPlantsException import com.terraformation.backend.tracking.event.ObservationPlotReplacedEvent import com.terraformation.backend.tracking.event.ObservationRescheduledEvent @@ -35,6 +37,7 @@ import com.terraformation.backend.tracking.event.ObservationScheduledEvent import com.terraformation.backend.tracking.event.ObservationStartedEvent import com.terraformation.backend.tracking.event.PlantingSiteDeletionStartedEvent import com.terraformation.backend.tracking.event.PlantingSiteMapEditedEvent +import com.terraformation.backend.tracking.model.MONITORING_PLOT_SIZE_INT import com.terraformation.backend.tracking.model.NewObservationModel import com.terraformation.backend.tracking.model.NotificationCriteria import com.terraformation.backend.tracking.model.PlantingSiteDepth @@ -58,6 +61,7 @@ class ObservationService( private val dslContext: DSLContext, private val eventPublisher: ApplicationEventPublisher, private val fileService: FileService, + private val monitoringPlotsDao: MonitoringPlotsDao, private val observationPhotosDao: ObservationPhotosDao, private val observationStore: ObservationStore, private val plantingSiteStore: PlantingSiteStore, @@ -287,6 +291,12 @@ class ObservationService( ?: throw PlotNotInObservationException(observationId, monitoringPlotId) val plantedSubzoneIds = plantingSiteStore.countReportedPlantsInSubzones(observation.plantingSiteId).keys + val monitoringPlotsRow = + monitoringPlotsDao.fetchOneById(observationPlot.model.monitoringPlotId) + + if (monitoringPlotsRow?.sizeMeters != MONITORING_PLOT_SIZE_INT) { + throw PlotSizeNotReplaceableException(observationId, monitoringPlotId) + } if (!allowCompleted && observationPlot.model.completedTime != null) { throw PlotAlreadyCompletedException(monitoringPlotId) diff --git a/src/main/kotlin/com/terraformation/backend/tracking/db/Exceptions.kt b/src/main/kotlin/com/terraformation/backend/tracking/db/Exceptions.kt index 92526bed7a27..f1db43be59b0 100644 --- a/src/main/kotlin/com/terraformation/backend/tracking/db/Exceptions.kt +++ b/src/main/kotlin/com/terraformation/backend/tracking/db/Exceptions.kt @@ -98,6 +98,13 @@ class PlotNotInObservationException( EntityNotFoundException( "Monitoring plot $monitoringPlotId is not assigned to observation $observationId") +class PlotSizeNotReplaceableException( + val observationId: ObservationId, + val monitoringPlotId: MonitoringPlotId +) : + MismatchedStateException( + "Monitoring plot $monitoringPlotId has old size; can't replace it in observation $observationId") + class ReassignmentExistsException(val plantingId: PlantingId) : MismatchedStateException( "Cannot reassign from planting $plantingId because it already has a reassignment") diff --git a/src/test/kotlin/com/terraformation/backend/tracking/ObservationServiceTest.kt b/src/test/kotlin/com/terraformation/backend/tracking/ObservationServiceTest.kt index d04127ce7376..0575392a1ac9 100644 --- a/src/test/kotlin/com/terraformation/backend/tracking/ObservationServiceTest.kt +++ b/src/test/kotlin/com/terraformation/backend/tracking/ObservationServiceTest.kt @@ -47,6 +47,7 @@ import com.terraformation.backend.tracking.db.PlantingSiteNotFoundException import com.terraformation.backend.tracking.db.PlantingSiteStore import com.terraformation.backend.tracking.db.PlotAlreadyCompletedException import com.terraformation.backend.tracking.db.PlotNotInObservationException +import com.terraformation.backend.tracking.db.PlotSizeNotReplaceableException import com.terraformation.backend.tracking.db.ScheduleObservationWithoutPlantsException import com.terraformation.backend.tracking.edit.PlantingSiteEdit import com.terraformation.backend.tracking.event.ObservationPlotReplacedEvent @@ -58,6 +59,7 @@ import com.terraformation.backend.tracking.event.PlantingSiteMapEditedEvent import com.terraformation.backend.tracking.model.ExistingObservationModel import com.terraformation.backend.tracking.model.ExistingPlantingSiteModel import com.terraformation.backend.tracking.model.MONITORING_PLOT_SIZE +import com.terraformation.backend.tracking.model.MONITORING_PLOT_SIZE_INT import com.terraformation.backend.tracking.model.NewObservationModel import com.terraformation.backend.tracking.model.NotificationCriteria import com.terraformation.backend.tracking.model.PlantingSiteDepth @@ -138,6 +140,7 @@ class ObservationServiceTest : DatabaseTest(), RunsAsUser { dslContext, eventPublisher, fileService, + monitoringPlotsDao, observationPhotosDao, observationStore, plantingSiteStore, @@ -1782,6 +1785,17 @@ class ObservationServiceTest : DatabaseTest(), RunsAsUser { } } + @Test + fun `throws exception if plot size is different from the size of newly-created plots`() { + val monitoringPlotId = insertMonitoringPlot(sizeMeters = MONITORING_PLOT_SIZE_INT - 1) + insertObservationPlot() + + assertThrows { + service.replaceMonitoringPlot( + observationId, monitoringPlotId, "justification", ReplacementDuration.LongTerm) + } + } + @Test fun `throws access denied exception if no permission to replace plot`() { val monitoringPlotId = insertMonitoringPlot() diff --git a/src/test/kotlin/com/terraformation/backend/tracking/PlotAssignmentTest.kt b/src/test/kotlin/com/terraformation/backend/tracking/PlotAssignmentTest.kt index 0ae9ecb16af4..545ac687e756 100644 --- a/src/test/kotlin/com/terraformation/backend/tracking/PlotAssignmentTest.kt +++ b/src/test/kotlin/com/terraformation/backend/tracking/PlotAssignmentTest.kt @@ -63,6 +63,7 @@ class PlotAssignmentTest : DatabaseTest(), RunsAsUser { dslContext, eventPublisher, mockk(), + monitoringPlotsDao, observationPhotosDao, observationStore, plantingSiteStore,