diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanSubthemeEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanSubthemeEntity.kt new file mode 100644 index 0000000000..f468e82fb0 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanSubthemeEntity.kt @@ -0,0 +1,8 @@ +package fr.gouv.cacem.monitorenv.domain.entities.controlPlan + +data class ControlPlanSubThemeEntity( + val id: Int, + val themeId: Int, + val subTheme: String, + val year: Int, +) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanTagEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanTagEntity.kt new file mode 100644 index 0000000000..ea4cead9d0 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanTagEntity.kt @@ -0,0 +1,7 @@ +package fr.gouv.cacem.monitorenv.domain.entities.controlPlan + +data class ControlPlanTagEntity( + val id: Int, + val tag: String, + val themeId: Int, +) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanThemeEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanThemeEntity.kt new file mode 100644 index 0000000000..613dcef66c --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlPlan/ControlPlanThemeEntity.kt @@ -0,0 +1,6 @@ +package fr.gouv.cacem.monitorenv.domain.entities.controlPlan + +data class ControlPlanThemeEntity( + val id: Int, + val theme: String, +) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlTheme/ControlThemeEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlTheme/ControlThemeEntity.kt index b5cd4eb4a5..c13754f5f3 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlTheme/ControlThemeEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/controlTheme/ControlThemeEntity.kt @@ -1,5 +1,6 @@ package fr.gouv.cacem.monitorenv.domain.entities.controlTheme +@Deprecated("Use ControlPlanSubThemesEntity instead") data class ControlThemeEntity( val id: Int, val themeLevel1: String, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionControlPlanEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionControlPlanEntity.kt new file mode 100644 index 0000000000..3dc60074c6 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionControlPlanEntity.kt @@ -0,0 +1,7 @@ +package fr.gouv.cacem.monitorenv.domain.entities.mission.envAction + +data class EnvActionControlPlanEntity( + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), + val tagIds: List? = emptyList(), +) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionEntity.kt index 64eb35fa94..13219a9a5f 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionEntity.kt @@ -21,8 +21,9 @@ import java.util.UUID abstract class EnvActionEntity( open val id: UUID, open val actionType: ActionTypeEnum, - open val actionStartDateTimeUtc: ZonedDateTime? = null, open val actionEndDateTimeUtc: ZonedDateTime? = null, + open val actionStartDateTimeUtc: ZonedDateTime? = null, + open val controlPlans: List? = listOf(), open val department: String? = null, open val facade: String? = null, open val geom: Geometry? = null, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceEntity.kt index 5720faffb3..64eeded94a 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceEntity.kt @@ -6,14 +6,15 @@ import java.util.UUID data class EnvActionSurveillanceEntity( override val id: UUID, - override val actionStartDateTimeUtc: ZonedDateTime? = null, override val actionEndDateTimeUtc: ZonedDateTime? = null, + override val actionStartDateTimeUtc: ZonedDateTime? = null, + override val controlPlans: List? = listOf(), override val geom: Geometry? = null, override val facade: String? = null, override val department: String? = null, - val themes: List? = listOf(), - val observations: String? = null, val coverMissionZone: Boolean? = null, + val observations: String? = null, + @Deprecated("Use controlPlan instead") val themes: List? = listOf(), ) : EnvActionEntity( actionType = ActionTypeEnum.SURVEILLANCE, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceProperties.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceProperties.kt index 68381345c9..0d1a51d030 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceProperties.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/EnvActionSurveillanceProperties.kt @@ -5,35 +5,37 @@ import java.time.ZonedDateTime import java.util.* data class EnvActionSurveillanceProperties( - val themes: List? = listOf(), - val observations: String? = null, val coverMissionZone: Boolean? = null, + val observations: String? = null, + @Deprecated("Use controlPlans instead") val themes: List? = listOf(), ) { fun toEnvActionSurveillanceEntity( id: UUID, actionStartDateTimeUtc: ZonedDateTime?, actionEndDateTimeUtc: ZonedDateTime?, - facade: String?, + controlPlans: List?, department: String?, + facade: String?, geom: Geometry?, ) = EnvActionSurveillanceEntity( id = id, actionStartDateTimeUtc = actionStartDateTimeUtc, actionEndDateTimeUtc = actionEndDateTimeUtc, - facade = facade, + controlPlans = controlPlans, + coverMissionZone = coverMissionZone, department = department, + facade = facade, geom = geom, - themes = themes, observations = observations, - coverMissionZone = coverMissionZone, + themes = themes, ) companion object { fun fromEnvActionSurveillanceEntity(envAction: EnvActionSurveillanceEntity) = EnvActionSurveillanceProperties( - themes = envAction.themes, - observations = envAction.observations, coverMissionZone = envAction.coverMissionZone, + observations = envAction.observations, + themes = envAction.themes, ) } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/ThemeEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/ThemeEntity.kt index fcd2333a83..7ed8ee5bf2 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/ThemeEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/ThemeEntity.kt @@ -1,5 +1,6 @@ package fr.gouv.cacem.monitorenv.domain.entities.mission.envAction +@Deprecated("Use EnvActionControlPlanSubThemeEntity instead") data class ThemeEntity( val theme: String? = null, val subThemes: List? = listOf(), diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlEntity.kt index fb009e5924..15e94287e1 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlEntity.kt @@ -2,6 +2,7 @@ package fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionCont import fr.gouv.cacem.monitorenv.domain.entities.VehicleTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ThemeEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.InfractionEntity @@ -11,21 +12,22 @@ import java.util.UUID data class EnvActionControlEntity( override val id: UUID, - override val actionStartDateTimeUtc: ZonedDateTime? = null, override val actionEndDateTimeUtc: ZonedDateTime? = null, - override val geom: Geometry? = null, - override val facade: String? = null, + override val actionStartDateTimeUtc: ZonedDateTime? = null, + override val controlPlans: List? = listOf(), override val department: String? = null, + override val facade: String? = null, + override val geom: Geometry? = null, override val isAdministrativeControl: Boolean? = null, override val isComplianceWithWaterRegulationsControl: Boolean? = null, override val isSafetyEquipmentAndStandardsComplianceControl: Boolean? = null, override val isSeafarersControl: Boolean? = null, - val themes: List? = listOf(), - val observations: String? = null, val actionNumberOfControls: Int? = null, val actionTargetType: ActionTargetTypeEnum? = null, - val vehicleType: VehicleTypeEnum? = null, val infractions: List? = listOf(), + val observations: String? = null, + @Deprecated("Use controlPlan instead") val themes: List? = listOf(), + val vehicleType: VehicleTypeEnum? = null, ) : EnvActionEntity( id = id, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlProperties.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlProperties.kt index 4d7988c555..a2e24cff09 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlProperties.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/mission/envAction/envActionControl/EnvActionControlProperties.kt @@ -1,6 +1,7 @@ package fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl import fr.gouv.cacem.monitorenv.domain.entities.VehicleTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ThemeEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.InfractionEntity import org.locationtech.jts.geom.Geometry @@ -8,19 +9,20 @@ import java.time.ZonedDateTime import java.util.UUID data class EnvActionControlProperties( - val themes: List? = listOf(), - val observations: String? = null, val actionNumberOfControls: Int? = null, val actionTargetType: ActionTargetTypeEnum? = null, - val vehicleType: VehicleTypeEnum? = null, val infractions: List? = listOf(), + val observations: String? = null, + @Deprecated("Use controlPlans instead") val themes: List? = listOf(), + val vehicleType: VehicleTypeEnum? = null, ) { fun toEnvActionControlEntity( id: UUID, - actionStartDateTimeUtc: ZonedDateTime?, actionEndDateTimeUtc: ZonedDateTime?, - facade: String?, + actionStartDateTimeUtc: ZonedDateTime?, + controlPlans: List?, department: String?, + facade: String?, geom: Geometry?, isAdministrativeControl: Boolean?, isComplianceWithWaterRegulationsControl: Boolean?, @@ -29,16 +31,14 @@ data class EnvActionControlProperties( ) = EnvActionControlEntity( id = id, - actionStartDateTimeUtc = actionStartDateTimeUtc, actionEndDateTimeUtc = actionEndDateTimeUtc, - facade = facade, - department = department, - geom = geom, - themes = themes, - observations = observations, actionNumberOfControls = actionNumberOfControls, + actionStartDateTimeUtc = actionStartDateTimeUtc, actionTargetType = actionTargetType, - vehicleType = vehicleType, + controlPlans = controlPlans, + department = department, + facade = facade, + geom = geom, infractions = infractions, isAdministrativeControl = isAdministrativeControl, isComplianceWithWaterRegulationsControl = @@ -46,17 +46,20 @@ data class EnvActionControlProperties( isSafetyEquipmentAndStandardsComplianceControl = isSafetyEquipmentAndStandardsComplianceControl, isSeafarersControl = isSeafarersControl, + observations = observations, + themes = themes, + vehicleType = vehicleType, ) companion object { fun fromEnvActionControlEntity(envAction: EnvActionControlEntity) = EnvActionControlProperties( - themes = envAction.themes, - observations = envAction.observations, actionNumberOfControls = envAction.actionNumberOfControls, actionTargetType = envAction.actionTargetType, - vehicleType = envAction.vehicleType, infractions = envAction.infractions, + observations = envAction.observations, + themes = envAction.themes, + vehicleType = envAction.vehicleType, ) } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/reporting/ReportingEntity.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/reporting/ReportingEntity.kt index ecb7bb2efa..0ca6723466 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/reporting/ReportingEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/entities/reporting/ReportingEntity.kt @@ -19,8 +19,8 @@ data class ReportingEntity( val seaFront: String? = null, val description: String? = null, val reportType: ReportingTypeEnum? = null, - val theme: String? = null, - val subThemes: List? = listOf(), + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), val actionTaken: String? = null, val isControlRequired: Boolean? = null, val hasNoUnitAvailable: Boolean? = null, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/mappers/EnvActionMapper.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/mappers/EnvActionMapper.kt index b1f81abe81..67493d44e9 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/mappers/EnvActionMapper.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/mappers/EnvActionMapper.kt @@ -2,6 +2,7 @@ package fr.gouv.cacem.monitorenv.domain.mappers import com.fasterxml.jackson.databind.ObjectMapper import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionNoteEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionNoteProperties @@ -22,17 +23,18 @@ object EnvActionMapper { fun getEnvActionEntityFromJSON( mapper: ObjectMapper, id: UUID, - actionStartDateTimeUtc: ZonedDateTime?, actionEndDateTimeUtc: ZonedDateTime?, - geom: Geometry?, actionType: ActionTypeEnum, - facade: String?, + actionStartDateTimeUtc: ZonedDateTime?, + controlPlans: List?, department: String?, - value: String?, + facade: String?, + geom: Geometry?, isAdministrativeControl: Boolean?, isComplianceWithWaterRegulationsControl: Boolean?, isSafetyEquipmentAndStandardsComplianceControl: Boolean?, isSeafarersControl: Boolean?, + value: String?, ): EnvActionEntity { return try { if (!value.isNullOrEmpty() && value != jsonbNullString) { @@ -43,12 +45,13 @@ object EnvActionMapper { EnvActionSurveillanceProperties::class.java, ) .toEnvActionSurveillanceEntity( - id, - actionStartDateTimeUtc, - actionEndDateTimeUtc, - facade, - department, - geom, + id = id, + actionEndDateTimeUtc = actionEndDateTimeUtc, + actionStartDateTimeUtc = actionStartDateTimeUtc, + controlPlans = controlPlans, + department = department, + facade = facade, + geom = geom, ) ActionTypeEnum.CONTROL -> mapper.readValue( @@ -56,16 +59,19 @@ object EnvActionMapper { EnvActionControlProperties::class.java, ) .toEnvActionControlEntity( - id, - actionStartDateTimeUtc, - actionEndDateTimeUtc, - facade, - department, - geom, - isAdministrativeControl, + id = id, + actionEndDateTimeUtc = actionEndDateTimeUtc, + actionStartDateTimeUtc = actionStartDateTimeUtc, + controlPlans = controlPlans, + department = department, + facade = facade, + geom = geom, + isAdministrativeControl = isAdministrativeControl, + isComplianceWithWaterRegulationsControl = isComplianceWithWaterRegulationsControl, + isSafetyEquipmentAndStandardsComplianceControl = isSafetyEquipmentAndStandardsComplianceControl, - isSeafarersControl, + isSeafarersControl = isSeafarersControl, ) ActionTypeEnum.NOTE -> mapper.readValue( @@ -73,8 +79,8 @@ object EnvActionMapper { EnvActionNoteProperties::class.java, ) .toEnvActionNoteEntity( - id, - actionStartDateTimeUtc, + id = id, + actionStartDateTimeUtc = actionStartDateTimeUtc, ) } } else { diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanSubThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanSubThemeRepository.kt new file mode 100644 index 0000000000..9e5392eda9 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanSubThemeRepository.kt @@ -0,0 +1,8 @@ +package fr.gouv.cacem.monitorenv.domain.repositories + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity + +interface IControlPlanSubThemeRepository { + fun findAll(): List + fun findByYear(year: Int): List +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanTagRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanTagRepository.kt new file mode 100644 index 0000000000..4df23ad13a --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanTagRepository.kt @@ -0,0 +1,8 @@ +package fr.gouv.cacem.monitorenv.domain.repositories + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity + +interface IControlPlanTagRepository { + fun findAll(): List + fun findByYear(year: Int): List +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanThemeRepository.kt new file mode 100644 index 0000000000..413466018f --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlPlanThemeRepository.kt @@ -0,0 +1,8 @@ +package fr.gouv.cacem.monitorenv.domain.repositories + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity + +interface IControlPlanThemeRepository { + fun findAll(): List + fun findByYear(year: Int): List +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlThemeRepository.kt index 3f0b145a7f..b6157c49dc 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlThemeRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/repositories/IControlThemeRepository.kt @@ -2,6 +2,7 @@ package fr.gouv.cacem.monitorenv.domain.repositories import fr.gouv.cacem.monitorenv.domain.entities.controlTheme.ControlThemeEntity +@Deprecated("Use IControlPlanSubThemeRepository instead") interface IControlThemeRepository { fun findById(controlThemeId: Int): ControlThemeEntity fun findAll(): List diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlans.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlans.kt new file mode 100644 index 0000000000..603a5bc3dd --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlans.kt @@ -0,0 +1,33 @@ +package fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan + +import fr.gouv.cacem.monitorenv.config.UseCase +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanTagRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanThemeRepository +import org.slf4j.LoggerFactory + +@UseCase +class GetControlPlans( + private val controlPlanThemeRepository: IControlPlanThemeRepository, + private val controlPlanSubThemeRepository: IControlPlanSubThemeRepository, + private val controlPlanTagRepository: IControlPlanTagRepository, +) { + private val logger = LoggerFactory.getLogger(GetControlPlans::class.java) + fun execute(): ControlPlanThemes { + val controlPlanThemes = controlPlanThemeRepository.findAll() + val controlPlanSubThemes = controlPlanSubThemeRepository.findAll() + val controlPlanTags = controlPlanTagRepository.findAll() + logger.info( + "Found ${controlPlanThemes.size} control plan themes, ${controlPlanSubThemes.size} subthemes, and ${controlPlanTags.size} tags ", + ) + return Triple(controlPlanThemes, controlPlanSubThemes, controlPlanTags) + } +} + +typealias ControlPlanThemes = Triple< + List, + List, + List,> diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansByYear.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansByYear.kt new file mode 100644 index 0000000000..9881f66689 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansByYear.kt @@ -0,0 +1,33 @@ +package fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan + +import fr.gouv.cacem.monitorenv.config.UseCase +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanTagRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanThemeRepository +import org.slf4j.LoggerFactory + +@UseCase +class GetControlPlansByYear( + private val controlPlanThemeRepository: IControlPlanThemeRepository, + private val controlPlanSubThemeRepository: IControlPlanSubThemeRepository, + private val controlPlanTagRepository: IControlPlanTagRepository, +) { + private val logger = LoggerFactory.getLogger(GetControlPlansByYear::class.java) + fun execute(year: Int): ControlPlanByYear { + val controlPlanThemes = controlPlanThemeRepository.findByYear(year) + val controlPlanSubThemes = controlPlanSubThemeRepository.findByYear(year) + val controlPlanTags = controlPlanTagRepository.findByYear(year) + logger.info("Found ${controlPlanSubThemes.size} control plan subthemes for year $year") + return Triple(controlPlanThemes, controlPlanSubThemes, controlPlanTags) + } +} + +typealias ControlPlanByYear = + Triple< + List, + List, + List, + > diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetAllControlThemes.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetAllControlThemes.kt index 03d8f3e59f..5039efa866 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetAllControlThemes.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetAllControlThemes.kt @@ -7,6 +7,7 @@ import fr.gouv.cacem.monitorenv.domain.entities.controlTheme.ControlThemeEntity import fr.gouv.cacem.monitorenv.domain.repositories.IControlThemeRepository import org.slf4j.LoggerFactory +@Deprecated("Use GetControlPlansByYear instead") @UseCase class GetAllControlThemes(private val controlThemeRepository: IControlThemeRepository) { private val logger = LoggerFactory.getLogger(GetAllControlThemes::class.java) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetControlThemeById.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetControlThemeById.kt index 285f7b9529..74eca6e04d 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetControlThemeById.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlThemes/GetControlThemeById.kt @@ -7,6 +7,7 @@ import fr.gouv.cacem.monitorenv.domain.entities.controlTheme.ControlThemeEntity import fr.gouv.cacem.monitorenv.domain.repositories.IControlThemeRepository import org.slf4j.LoggerFactory +@Deprecated("Not used") @UseCase class GetControlThemeById(private val controlThemeRepository: IControlThemeRepository) { private val logger = LoggerFactory.getLogger(GetControlThemeById::class.java) diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithAttachedReporting.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithAttachedReporting.kt index dd70348738..aa6f3707e2 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithAttachedReporting.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/CreateOrUpdateMissionWithAttachedReporting.kt @@ -6,8 +6,8 @@ import fr.gouv.cacem.monitorenv.config.UseCase import fr.gouv.cacem.monitorenv.domain.entities.mission.* import fr.gouv.cacem.monitorenv.domain.repositories.IMissionRepository import fr.gouv.cacem.monitorenv.domain.repositories.IReportingRepository +import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.EnvActionAttachedToReportingIds import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.MissionDTO -import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.inputs.missions.EnvActionAttachedToReportingIds import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.exceptions.ReportingAlreadyAttachedException import org.slf4j.LoggerFactory import java.util.UUID diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/dtos/MissionDTO.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/dtos/MissionDTO.kt index f2216404d3..69bd0d9635 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/dtos/MissionDTO.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/dtos/MissionDTO.kt @@ -2,7 +2,6 @@ package fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.use_cases.reportings.dtos.ReportingDTO -import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.inputs.missions.EnvActionAttachedToReportingIds import java.util.UUID data class MissionDTO( diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/CreateOrUpdateReportingDataInput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/CreateOrUpdateReportingDataInput.kt index 89be994ecc..2b7473089f 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/CreateOrUpdateReportingDataInput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/CreateOrUpdateReportingDataInput.kt @@ -23,8 +23,8 @@ data class CreateOrUpdateReportingDataInput( val geom: Geometry? = null, val description: String? = null, val reportType: ReportingTypeEnum? = null, - val theme: String? = null, - val subThemes: List? = listOf(), + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), val actionTaken: String? = null, val isControlRequired: Boolean? = null, val hasNoUnitAvailable: Boolean? = null, @@ -51,8 +51,8 @@ data class CreateOrUpdateReportingDataInput( geom = this.geom, description = this.description, reportType = this.reportType, - theme = this.theme, - subThemes = this.subThemes, + themeId = this.themeId, + subThemeIds = this.subThemeIds, actionTaken = this.actionTaken, isControlRequired = this.isControlRequired, hasNoUnitAvailable = this.hasNoUnitAvailable, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/CreateOrUpdateMissionDataInput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/CreateOrUpdateMissionDataInput.kt index bc818b1d69..b6028afd10 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/CreateOrUpdateMissionDataInput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/CreateOrUpdateMissionDataInput.kt @@ -5,28 +5,28 @@ import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.EnvActionAttachedToReportingIds import org.locationtech.jts.geom.MultiPolygon import java.time.ZonedDateTime -import java.util.UUID data class CreateOrUpdateMissionDataInput( val id: Int? = null, - val missionTypes: List, + val attachedReportingIds: List, val controlUnits: List = listOf(), - val openBy: String? = null, val closedBy: String? = null, - val observationsCacem: String? = null, - val observationsCnsp: String? = null, + val envActions: List? = null, val facade: String? = null, val geom: MultiPolygon? = null, - val startDateTimeUtc: ZonedDateTime, - val endDateTimeUtc: ZonedDateTime? = null, - val missionSource: MissionSourceEnum, - val isClosed: Boolean, - val envActions: List? = null, val hasMissionOrder: Boolean? = false, + val isClosed: Boolean, val isUnderJdp: Boolean? = false, - val attachedReportingIds: List, + val missionSource: MissionSourceEnum, + val missionTypes: List, + val observationsCacem: String? = null, + val observationsCnsp: String? = null, + val openBy: String? = null, + val startDateTimeUtc: ZonedDateTime, + val endDateTimeUtc: ZonedDateTime? = null, ) { fun toMissionEntity(): MissionEntity { val hasMissionOrder = this.hasMissionOrder ?: false @@ -34,23 +34,23 @@ data class CreateOrUpdateMissionDataInput( return MissionEntity( id = this.id, - missionTypes = this.missionTypes, - controlUnits = this.controlUnits, - openBy = this.openBy, closedBy = this.closedBy, - observationsCacem = this.observationsCacem, - observationsCnsp = this.observationsCnsp, + controlUnits = this.controlUnits, + endDateTimeUtc = this.endDateTimeUtc, + envActions = this.envActions?.map { it.toEnvActionEntity() }, facade = this.facade, geom = this.geom, - startDateTimeUtc = this.startDateTimeUtc, - endDateTimeUtc = this.endDateTimeUtc, + hasMissionOrder = hasMissionOrder, isClosed = this.isClosed, isDeleted = false, - missionSource = this.missionSource, - envActions = this.envActions?.map { it.toEnvActionEntity() }, - hasMissionOrder = hasMissionOrder, - isUnderJdp = isUnderJdp, isGeometryComputedFromControls = false, + isUnderJdp = isUnderJdp, + missionSource = this.missionSource, + missionTypes = this.missionTypes, + observationsCacem = this.observationsCacem, + observationsCnsp = this.observationsCnsp, + openBy = this.openBy, + startDateTimeUtc = this.startDateTimeUtc, ) } @@ -64,5 +64,3 @@ data class CreateOrUpdateMissionDataInput( ?: listOf() } } - -typealias EnvActionAttachedToReportingIds = Pair> diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionControlPlanDataInput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionControlPlanDataInput.kt new file mode 100644 index 0000000000..0eeaab81fc --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionControlPlanDataInput.kt @@ -0,0 +1,17 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.inputs.missions + +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity + +data class MissionEnvActionControlPlanDataInput( + val subThemeIds: List? = emptyList(), + val tagIds: List? = emptyList(), + val themeId: Int? = null, +) { + fun toEnvActionControlPlanEntity(): EnvActionControlPlanEntity { + return EnvActionControlPlanEntity( + subThemeIds = this.subThemeIds, + tagIds = this.tagIds, + themeId = this.themeId, + ) + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionDataInput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionDataInput.kt index 70eb9df70c..80d0ce145f 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionDataInput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/inputs/missions/MissionEnvActionDataInput.kt @@ -23,7 +23,8 @@ data class MissionEnvActionDataInput( // EnvActionControl + EnvSurveillance Properties val actionEndDateTimeUtc: ZonedDateTime? = null, - val themes: List? = null, + val controlPlans: List? = null, + @Deprecated("Use controlPlans instead") val themes: List? = null, val department: String? = null, val facade: String? = null, val geom: Geometry? = null, @@ -68,29 +69,33 @@ data class MissionEnvActionDataInput( ActionTypeEnum.CONTROL -> return EnvActionControlEntity( id = this.id, - actionStartDateTimeUtc = this.actionStartDateTimeUtc, actionEndDateTimeUtc = this.actionEndDateTimeUtc, + actionNumberOfControls = this.actionNumberOfControls, + actionTargetType = this.actionTargetType, + actionStartDateTimeUtc = this.actionStartDateTimeUtc, + controlPlans = + this.controlPlans?.map { it.toEnvActionControlPlanEntity() }, department = this.department, facade = this.facade, geom = this.geom, - themes = this.themes, - actionNumberOfControls = this.actionNumberOfControls, - actionTargetType = this.actionTargetType, - vehicleType = this.vehicleType, infractions = this.infractions?.map { it.toInfractionEntity() }, - observations = this.observations, isAdministrativeControl = this.isAdministrativeControl, isComplianceWithWaterRegulationsControl = this.isComplianceWithWaterRegulationsControl, isSafetyEquipmentAndStandardsComplianceControl = this.isSafetyEquipmentAndStandardsComplianceControl, isSeafarersControl = this.isSeafarersControl, + observations = this.observations, + themes = this.themes, + vehicleType = this.vehicleType, ) ActionTypeEnum.SURVEILLANCE -> return EnvActionSurveillanceEntity( id = this.id, actionStartDateTimeUtc = this.actionStartDateTimeUtc, actionEndDateTimeUtc = this.actionEndDateTimeUtc, + controlPlans = + this.controlPlans?.map { it.toEnvActionControlPlanEntity() }, department = this.department, facade = this.facade, geom = this.geom, @@ -108,3 +113,5 @@ data class MissionEnvActionDataInput( } } } + +typealias ControlPlanSubThemeDataInput = Pair> diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/AttachedReportingDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/AttachedReportingDataOutput.kt index 4e8ac379f0..b2e7c177f3 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/AttachedReportingDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/AttachedReportingDataOutput.kt @@ -27,8 +27,8 @@ data class AttachedReportingDataOutput( val seaFront: String? = null, val description: String? = null, val reportType: ReportingTypeEnum? = null, - val theme: String? = null, - val subThemes: List? = listOf(), + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), val actionTaken: String? = null, val isControlRequired: Boolean? = null, val hasNoUnitAvailable: Boolean? = null, @@ -76,8 +76,8 @@ data class AttachedReportingDataOutput( seaFront = dto.reporting.seaFront, description = dto.reporting.description, reportType = dto.reporting.reportType, - theme = dto.reporting.theme, - subThemes = dto.reporting.subThemes, + themeId = dto.reporting.themeId, + subThemeIds = dto.reporting.subThemeIds, actionTaken = dto.reporting.actionTaken, isControlRequired = dto.reporting.isControlRequired, hasNoUnitAvailable = dto.reporting.hasNoUnitAvailable, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanDataOutput.kt new file mode 100644 index 0000000000..90d9dbe6f4 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanDataOutput.kt @@ -0,0 +1,28 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity + +data class ControlPlanDataOutput( + val themes: Map, + val subThemes: Map, + val tags: Map, +) { + companion object { + fun fromControlPlanEntities( + themes: List, + subThemes: List, + tags: List, + ): ControlPlanDataOutput { + return ControlPlanDataOutput( + themes = themes.associateBy({ it.id }, { ControlPlanThemeDataOutput.fromControlPlanThemeEntity(it) }), + subThemes = subThemes.associateBy( + { it.id }, + { ControlPlanSubThemeDataOutput.fromControlPlanSubThemeEntity(it) }, + ), + tags = tags.associateBy({ it.id }, { ControlPlanTagDataOutput.fromControlPlanTagEntity(it) }), + ) + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanSubThemeDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanSubThemeDataOutput.kt new file mode 100644 index 0000000000..2c5ce4f144 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanSubThemeDataOutput.kt @@ -0,0 +1,20 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity + +data class ControlPlanSubThemeDataOutput( + val id: Int, + val themeId: Int, + val subTheme: String, + val year: Int, +) { + companion object { + fun fromControlPlanSubThemeEntity(controlPlanSubTheme: ControlPlanSubThemeEntity) = + ControlPlanSubThemeDataOutput( + id = controlPlanSubTheme.id, + themeId = controlPlanSubTheme.themeId, + subTheme = controlPlanSubTheme.subTheme, + year = controlPlanSubTheme.year, + ) + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanTagDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanTagDataOutput.kt new file mode 100644 index 0000000000..eb5435419c --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanTagDataOutput.kt @@ -0,0 +1,18 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity + +data class ControlPlanTagDataOutput( + val id: Int, + val tag: String, + val themeId: Int, +) { + companion object { + fun fromControlPlanTagEntity(controlPlanTag: ControlPlanTagEntity) = + ControlPlanTagDataOutput( + id = controlPlanTag.id, + tag = controlPlanTag.tag, + themeId = controlPlanTag.themeId, + ) + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanThemeDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanThemeDataOutput.kt new file mode 100644 index 0000000000..53a22bfc0c --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ControlPlanThemeDataOutput.kt @@ -0,0 +1,19 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity + +data class ControlPlanThemeDataOutput( + val id: Int, + val theme: String, +) { + companion object { + fun fromControlPlanThemeEntity( + controlPlanThemeEntity: ControlPlanThemeEntity, + ): ControlPlanThemeDataOutput { + return ControlPlanThemeDataOutput( + id = controlPlanThemeEntity.id, + theme = controlPlanThemeEntity.theme, + ) + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingDataOutput.kt index 36a88ce454..2805d5587a 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingDataOutput.kt @@ -29,8 +29,8 @@ data class ReportingDataOutput( val seaFront: String? = null, val description: String? = null, val reportType: ReportingTypeEnum? = null, - val theme: String? = null, - val subThemes: List? = listOf(), + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), val actionTaken: String? = null, val isControlRequired: Boolean? = null, val hasNoUnitAvailable: Boolean? = null, @@ -91,8 +91,8 @@ data class ReportingDataOutput( seaFront = dto.reporting.seaFront, description = dto.reporting.description, reportType = dto.reporting.reportType, - theme = dto.reporting.theme, - subThemes = dto.reporting.subThemes, + themeId = dto.reporting.themeId, + subThemeIds = dto.reporting.subThemeIds, actionTaken = dto.reporting.actionTaken, isControlRequired = dto.reporting.isControlRequired, hasNoUnitAvailable = dto.reporting.hasNoUnitAvailable, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingsDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingsDataOutput.kt index c936fe6eef..401aba82ec 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingsDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/ReportingsDataOutput.kt @@ -26,8 +26,8 @@ data class ReportingsDataOutput( val seaFront: String? = null, val description: String? = null, val reportType: ReportingTypeEnum? = null, - val theme: String? = null, - val subThemes: List? = listOf(), + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), val actionTaken: String? = null, val isControlRequired: Boolean? = null, val hasNoUnitAvailable: Boolean? = null, @@ -68,8 +68,8 @@ data class ReportingsDataOutput( seaFront = dto.reporting.seaFront, description = dto.reporting.description, reportType = dto.reporting.reportType, - theme = dto.reporting.theme, - subThemes = dto.reporting.subThemes, + themeId = dto.reporting.themeId, + subThemeIds = dto.reporting.subThemeIds, actionTaken = dto.reporting.actionTaken, isControlRequired = dto.reporting.isControlRequired, hasNoUnitAvailable = dto.reporting.hasNoUnitAvailable, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionAttachedReportingDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionAttachedReportingDataOutput.kt index 93acf82c5c..5adb514c41 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionAttachedReportingDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionAttachedReportingDataOutput.kt @@ -29,8 +29,8 @@ data class MissionAttachedReportingDataOutput( val seaFront: String? = null, val description: String? = null, val reportType: ReportingTypeEnum? = null, - val theme: String? = null, - val subThemes: List? = listOf(), + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), val actionTaken: String? = null, val isControlRequired: Boolean? = null, val hasNoUnitAvailable: Boolean? = null, @@ -89,8 +89,8 @@ data class MissionAttachedReportingDataOutput( seaFront = dto.reporting.seaFront, description = dto.reporting.description, reportType = dto.reporting.reportType, - theme = dto.reporting.theme, - subThemes = dto.reporting.subThemes, + themeId = dto.reporting.themeId, + subThemeIds = dto.reporting.subThemeIds, actionTaken = dto.reporting.actionTaken, isControlRequired = dto.reporting.isControlRequired, hasNoUnitAvailable = dto.reporting.hasNoUnitAvailable, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlDataOutput.kt index cbeef65c17..142dab4b46 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlDataOutput.kt @@ -17,6 +17,7 @@ data class MissionEnvActionControlDataOutput( override val actionStartDateTimeUtc: ZonedDateTime? = null, val actionTargetType: ActionTargetTypeEnum? = null, override val actionType: ActionTypeEnum = ActionTypeEnum.CONTROL, + val controlPlans: List? = listOf(), val department: String? = null, val facade: String? = null, val geom: Geometry? = null, @@ -27,7 +28,7 @@ data class MissionEnvActionControlDataOutput( val isSeafarersControl: Boolean? = null, val observations: String? = null, val reportingIds: List, - val themes: List? = listOf(), + @Deprecated("Use controlPlans instead") val themes: List? = listOf(), val vehicleType: VehicleTypeEnum? = null, ) : MissionEnvActionDataOutput( @@ -46,6 +47,11 @@ data class MissionEnvActionControlDataOutput( actionStartDateTimeUtc = envActionControlEntity.actionStartDateTimeUtc, actionEndDateTimeUtc = envActionControlEntity.actionEndDateTimeUtc, actionTargetType = envActionControlEntity.actionTargetType, + controlPlans = + envActionControlEntity.controlPlans?.map { + MissionEnvActionControlPlanDataOutput + .fromEnvActionControlPlanEntity(it) + }, department = envActionControlEntity.department, facade = envActionControlEntity.facade, geom = envActionControlEntity.geom, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlPlanDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlPlanDataOutput.kt new file mode 100644 index 0000000000..1b98751b5c --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionControlPlanDataOutput.kt @@ -0,0 +1,18 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.missions + +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity + +data class MissionEnvActionControlPlanDataOutput( + val themeId: Int? = null, + val subThemeIds: List? = emptyList(), + val tagIds: List? = emptyList(), +) { + companion object { + fun fromEnvActionControlPlanEntity(envActionControlPlanEntity: EnvActionControlPlanEntity) = + MissionEnvActionControlPlanDataOutput( + subThemeIds = envActionControlPlanEntity.subThemeIds, + tagIds = envActionControlPlanEntity.tagIds, + themeId = envActionControlPlanEntity.themeId, + ) + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionDataOutput.kt index 86f15aee01..2072a27e04 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionDataOutput.kt @@ -1,6 +1,11 @@ package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.missions import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionNoteEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionSurveillanceEntity +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.EnvActionControlEntity +import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.EnvActionAttachedToReportingIds import java.time.ZonedDateTime import java.util.UUID @@ -8,4 +13,37 @@ abstract class MissionEnvActionDataOutput( open val id: UUID, open val actionStartDateTimeUtc: ZonedDateTime? = null, open val actionType: ActionTypeEnum, -) +) { + companion object { + fun fromEnvActionEntity( + envActionEntity: EnvActionEntity, + envActionsAttachedToReportingIds: List?, + ): MissionEnvActionDataOutput { + return when (envActionEntity.actionType) { + ActionTypeEnum.CONTROL -> + MissionEnvActionControlDataOutput.fromEnvActionControlEntity( + envActionControlEntity = envActionEntity as EnvActionControlEntity, + reportingIds = + envActionsAttachedToReportingIds + ?.find { id -> id.first == envActionEntity.id } + ?.second + ?: listOf(), + ) + ActionTypeEnum.SURVEILLANCE -> + MissionEnvActionSurveillanceDataOutput.fromEnvActionSurveillanceEntity( + envActionSurveillanceEntity = + envActionEntity as EnvActionSurveillanceEntity, + reportingIds = + envActionsAttachedToReportingIds + ?.find { id -> id.first == envActionEntity.id } + ?.second + ?: listOf(), + ) + ActionTypeEnum.NOTE -> + MissionEnvActionNoteDataOutput.fromEnvActionNoteEntity( + envActionEntity as EnvActionNoteEntity, + ) + } + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionSurveillanceDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionSurveillanceDataOutput.kt index 6c9c7487eb..1832937a5c 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionSurveillanceDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionEnvActionSurveillanceDataOutput.kt @@ -12,12 +12,14 @@ data class MissionEnvActionSurveillanceDataOutput( val actionEndDateTimeUtc: ZonedDateTime? = null, override val actionStartDateTimeUtc: ZonedDateTime? = null, override val actionType: ActionTypeEnum = ActionTypeEnum.SURVEILLANCE, + val controlPlans: List? = null, val coverMissionZone: Boolean? = null, val department: String? = null, val facade: String? = null, val geom: Geometry? = null, val observations: String? = null, val reportingIds: List, + @Deprecated("Use controlPlans instead") val themes: List? = listOf(), ) : MissionEnvActionDataOutput( @@ -34,6 +36,9 @@ data class MissionEnvActionSurveillanceDataOutput( id = envActionSurveillanceEntity.id, actionEndDateTimeUtc = envActionSurveillanceEntity.actionEndDateTimeUtc, actionStartDateTimeUtc = envActionSurveillanceEntity.actionStartDateTimeUtc, + controlPlans = envActionSurveillanceEntity.controlPlans?.map { + MissionEnvActionControlPlanDataOutput.fromEnvActionControlPlanEntity(it) + }, department = envActionSurveillanceEntity.department, facade = envActionSurveillanceEntity.facade, geom = envActionSurveillanceEntity.geom, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionsDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionsDataOutput.kt index 199f58b287..463553c2a1 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionsDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/adapters/bff/outputs/missions/MissionsDataOutput.kt @@ -3,7 +3,6 @@ package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.mission import fr.gouv.cacem.monitorenv.domain.entities.controlUnit.LegacyControlUnitEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.MissionDTO import org.locationtech.jts.geom.MultiPolygon import java.time.ZonedDateTime @@ -20,7 +19,7 @@ data class MissionsDataOutput( val geom: MultiPolygon? = null, val startDateTimeUtc: ZonedDateTime, val endDateTimeUtc: ZonedDateTime? = null, - val envActions: List? = null, + val envActions: List? = null, val missionSource: MissionSourceEnum, val isClosed: Boolean, val hasMissionOrder: Boolean, @@ -43,7 +42,12 @@ data class MissionsDataOutput( geom = dto.mission.geom, startDateTimeUtc = dto.mission.startDateTimeUtc, endDateTimeUtc = dto.mission.endDateTimeUtc, - envActions = dto.mission.envActions, + envActions = dto.mission.envActions?.map { + MissionEnvActionDataOutput.fromEnvActionEntity( + envActionEntity = it, + envActionsAttachedToReportingIds = dto.envActionsAttachedToReportingIds, + ) + }, missionSource = dto.mission.missionSource, isClosed = dto.mission.isClosed, hasMissionOrder = dto.mission.hasMissionOrder, diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlPlansController.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlPlansController.kt new file mode 100644 index 0000000000..a8b487b5c9 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlPlansController.kt @@ -0,0 +1,53 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.endpoints.bff + +import fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan.GetControlPlans +import fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan.GetControlPlansByYear +import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.ControlPlanDataOutput +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.websocket.server.PathParam +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/bff/v1/control_plans") +@Tag( + name = "Control Plan Themes, SubThemes and tags", + description = "API des sous thématiques des plan de contrôle", +) +class ControlPlansController( + private val getControlPlans: GetControlPlans, + private val getControlPlansByYear: GetControlPlansByYear, +) { + + @GetMapping("") + @Operation(summary = "Get control plan themes, subthemes and tags and allowed tags") + fun getAll(): ControlPlanDataOutput { + val controlPlan = getControlPlans.execute() + return ControlPlanDataOutput.fromControlPlanEntities( + themes = controlPlan.first, + subThemes = controlPlan.second, + tags = controlPlan.third, + ) + } + + @GetMapping("/{year}") + @Operation( + summary = + "Get control plan themes, subthemes and tags and allowed tags for a given year", + ) + fun getControlPlansByYear( + @PathParam("validity year of the control plan themes") + @PathVariable(name = "year") + year: Int, + ): ControlPlanDataOutput { + val controlPlan = getControlPlansByYear.execute(year) + return ControlPlanDataOutput.fromControlPlanEntities( + themes = controlPlan.first, + subThemes = controlPlan.second, + tags = controlPlan.third, + ) + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlThemesController.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlThemesController.kt index 67e56f248a..fe39e6cb85 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlThemesController.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlThemesController.kt @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +@Deprecated("Use ControlPlanSubThemesController instead") @RestController @RequestMapping("/bff/v1/controlthemes") @Tag(name = "BFF.Control Themes", description = "API control themes") diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanSubThemeModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanSubThemeModel.kt new file mode 100644 index 0000000000..a5b8c5a014 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanSubThemeModel.kt @@ -0,0 +1,50 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.Hibernate +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy + +@Entity +@Table(name = "control_plan_sub_themes") +@Cache( + usage = CacheConcurrencyStrategy.READ_WRITE, +) +class ControlPlanSubThemeModel( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false, updatable = false) + val id: Int, + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "theme_id") + val controlPlanTheme: ControlPlanThemeModel, + @Column(name = "subtheme") val subTheme: String, + @Column(name = "year") val year: Int, +) { + fun toControlPlanSubThemeEntity() = + ControlPlanSubThemeEntity( + id = id, + themeId = controlPlanTheme.id, + subTheme = subTheme, + year = year, + ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as ControlPlanSubThemeModel + + return id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanTagModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanTagModel.kt new file mode 100644 index 0000000000..1de80039f7 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanTagModel.kt @@ -0,0 +1,48 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.Hibernate +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy + +@Entity +@Table(name = "control_plan_tags") +@Cache( + usage = CacheConcurrencyStrategy.READ_WRITE, +) +class ControlPlanTagModel( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false, updatable = false) + val id: Int, + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "theme_id") + val controlPlanTheme: ControlPlanThemeModel, + @Column(name = "tag") val tag: String, +) { + fun toControlPlanTagEntity() = + ControlPlanTagEntity( + id = this.id, + tag = this.tag, + themeId = this.controlPlanTheme.id, + ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as ControlPlanTagModel + + return id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanThemeModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanThemeModel.kt new file mode 100644 index 0000000000..6016cc6a1e --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ControlPlanThemeModel.kt @@ -0,0 +1,33 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.Hibernate + +@Entity +@Table(name = "control_plan_themes") +data class ControlPlanThemeModel( + @Id + @Column(name = "id") + val id: Int, + @Column(name = "theme") + val theme: String, +) { + fun toControlPlanThemeEntity() = ControlPlanThemeEntity( + id = id, + theme = theme, + ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as ControlPlanThemeModel + + return id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionModel.kt index 225a1adb7f..14a3551539 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionModel.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionModel.kt @@ -8,9 +8,11 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionEntity import fr.gouv.cacem.monitorenv.domain.mappers.EnvActionMapper import io.hypersistence.utils.hibernate.type.json.JsonBinaryType +import jakarta.persistence.CascadeType import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.EnumType @@ -38,7 +40,7 @@ import java.util.UUID ) @Entity @Table(name = "env_actions") -data class EnvActionModel( +class EnvActionModel( @Id @JdbcType(UUIDJdbcType::class) @Column(name = "id", nullable = false, updatable = false, columnDefinition = "uuid") @@ -57,7 +59,7 @@ data class EnvActionModel( val value: String, @Column(name = "facade") val facade: String? = null, @Column(name = "department") val department: String? = null, - @ManyToOne(fetch = FetchType.EAGER, optional = false) + @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "mission_id") @JsonBackReference val mission: MissionModel, @@ -68,54 +70,134 @@ data class EnvActionModel( val isSafetyEquipmentAndStandardsComplianceControl: Boolean? = null, @Column(name = "is_seafarers_control") val isSeafarersControl: Boolean? = null, @OneToMany( - fetch = FetchType.EAGER, + fetch = FetchType.LAZY, mappedBy = "attachedEnvAction", ) @JsonManagedReference val attachedReporting: List? = listOf(), + @OneToMany( + fetch = FetchType.EAGER, + cascade = [CascadeType.ALL], + orphanRemoval = true, + mappedBy = "envAction", + ) + val controlPlanThemes: MutableList? = ArrayList(), + @OneToMany( + fetch = FetchType.EAGER, + cascade = [CascadeType.ALL], + orphanRemoval = true, + mappedBy = "envAction", + ) + val controlPlanSubThemes: MutableList? = ArrayList(), + @OneToMany( + fetch = FetchType.EAGER, + cascade = [CascadeType.ALL], + orphanRemoval = true, + mappedBy = "envAction", + ) + val controlPlanTags: MutableList? = ArrayList(), ) { fun toActionEntity(mapper: ObjectMapper): EnvActionEntity { + val controlPlans = + controlPlanThemes?.map { it -> + EnvActionControlPlanEntity( + themeId = it.id.themeId, + subThemeIds = + controlPlanSubThemes + ?.filter { subTheme -> + it.id.themeId == + subTheme.controlPlanSubTheme + ?.controlPlanTheme + ?.id + } + ?.map { it.id.subthemeId }, + tagIds = + controlPlanTags + ?.filter { tag -> + it.id.themeId == + tag.controlPlanTag?.controlPlanTheme?.id + } + ?.map { it.id.tagId }, + ) + } + return EnvActionMapper.getEnvActionEntityFromJSON( mapper = mapper, id = id, - actionStartDateTimeUtc = actionStartDateTime?.atZone(UTC), actionEndDateTimeUtc = actionEndDateTime?.atZone(UTC), - geom = geom, actionType = actionType, - facade = facade, + actionStartDateTimeUtc = actionStartDateTime?.atZone(UTC), + controlPlans = controlPlans, department = department, - value = value, + facade = facade, + geom = geom, isAdministrativeControl = isAdministrativeControl, isComplianceWithWaterRegulationsControl = isComplianceWithWaterRegulationsControl, isSafetyEquipmentAndStandardsComplianceControl = isSafetyEquipmentAndStandardsComplianceControl, isSeafarersControl = isSeafarersControl, + value = value, ) } companion object { fun fromEnvActionEntity( action: EnvActionEntity, mission: MissionModel, + controlPlanThemesReferenceModelMap: Map, + controlPlanSubThemesReferenceModelMap: Map, + controlPlanTagsReferenceModelMap: Map, mapper: ObjectMapper, - ) = - EnvActionModel( - id = action.id, - actionType = action.actionType, - actionStartDateTime = action.actionStartDateTimeUtc?.toInstant(), - actionEndDateTime = action.actionEndDateTimeUtc?.toInstant(), - facade = action.facade, - department = action.department, - value = EnvActionMapper.envActionEntityToJSON(mapper, action), - mission = mission, - geom = action.geom, - isAdministrativeControl = action.isAdministrativeControl, - isComplianceWithWaterRegulationsControl = - action.isComplianceWithWaterRegulationsControl, - isSafetyEquipmentAndStandardsComplianceControl = - action.isSafetyEquipmentAndStandardsComplianceControl, - isSeafarersControl = action.isSeafarersControl, - ) + ): EnvActionModel { + val envActionModel = + EnvActionModel( + id = action.id, + actionEndDateTime = action.actionEndDateTimeUtc?.toInstant(), + actionType = action.actionType, + actionStartDateTime = action.actionStartDateTimeUtc?.toInstant(), + department = action.department, + facade = action.facade, + isAdministrativeControl = action.isAdministrativeControl, + isComplianceWithWaterRegulationsControl = + action.isComplianceWithWaterRegulationsControl, + isSafetyEquipmentAndStandardsComplianceControl = + action.isSafetyEquipmentAndStandardsComplianceControl, + isSeafarersControl = action.isSeafarersControl, + mission = mission, + geom = action.geom, + value = EnvActionMapper.envActionEntityToJSON(mapper, action), + ) + action.controlPlans?.forEach { + if (it.themeId == null) return@forEach + envActionModel.controlPlanThemes?.add( + EnvActionsControlPlanThemeModel.fromEnvActionControlPlanThemeEntity( + envAction = envActionModel, + controlPlanTheme = controlPlanThemesReferenceModelMap[it.themeId]!!, + ), + ) + it.subThemeIds?.forEach { subThemeId -> + envActionModel.controlPlanSubThemes?.add( + EnvActionsControlPlanSubThemeModel + .fromEnvActionControlPlanSubThemeEntity( + envAction = envActionModel, + controlPlanSubTheme = + controlPlanSubThemesReferenceModelMap[ + subThemeId, + ]!!, + ), + ) + } + it.tagIds?.forEach { tagId -> + envActionModel.controlPlanTags?.add( + EnvActionsControlPlanTagModel.fromEnvActionControlPlanTagEntity( + envAction = envActionModel, + controlPlanTag = controlPlanTagsReferenceModelMap[tagId]!!, + ), + ) + } + } + return envActionModel + } } override fun equals(other: Any?): Boolean { @@ -127,10 +209,4 @@ data class EnvActionModel( } override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + - "(id = $id , geom = $geom , actionStartDateTime = $actionStartDateTime, actionEndDateTime = $actionEndDateTime, actionType = $actionType , value = $value, facade = $facade, department = $department, isAdministrativeControl = $isAdministrativeControl, isComplianceWithWaterRegulationsControl = $isComplianceWithWaterRegulationsControl, isSeafarersControl = $isSeafarersControl, isSafetyEquipmentAndStandardsComplianceControl = $isSafetyEquipmentAndStandardsComplianceControl )" - } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanSubThemeModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanSubThemeModel.kt new file mode 100644 index 0000000000..e03a108ed7 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanSubThemeModel.kt @@ -0,0 +1,71 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import jakarta.persistence.Column +import jakarta.persistence.Embeddable +import jakarta.persistence.EmbeddedId +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.MapsId +import jakarta.persistence.Table +import org.hibernate.Hibernate +import java.io.Serializable +import java.util.UUID + +@Entity +@Table(name = "env_actions_control_plan_sub_themes") +class EnvActionsControlPlanSubThemeModel( + @EmbeddedId val id: EnvActionsSubThemePk, + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("envActionId") + @JoinColumn(name = "env_action_id") + val envAction: EnvActionModel? = null, + @ManyToOne(fetch = FetchType.EAGER) + @MapsId("subthemeId") + @JoinColumn(name = "subtheme_id") + val controlPlanSubTheme: ControlPlanSubThemeModel? = null, +) { + companion object { + fun fromEnvActionControlPlanSubThemeEntity( + envAction: EnvActionModel, + controlPlanSubTheme: ControlPlanSubThemeModel, + ) = + EnvActionsControlPlanSubThemeModel( + id = + EnvActionsSubThemePk( + envActionId = envAction.id, + subthemeId = controlPlanSubTheme.id, + ), + envAction = envAction, + controlPlanSubTheme = controlPlanSubTheme, + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as EnvActionsControlPlanSubThemeModel + + return id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} + +@Embeddable +data class EnvActionsSubThemePk( + @Column(name = "env_action_id") val envActionId: UUID, + @Column(name = "subtheme_id") val subthemeId: Int, +) : Serializable { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is EnvActionsSubThemePk) return false + + return envActionId == other.envActionId && subthemeId == other.subthemeId + } + + override fun hashCode(): Int { + return listOf(envActionId, subthemeId).hashCode() + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanTagModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanTagModel.kt new file mode 100644 index 0000000000..0d6d5b750c --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanTagModel.kt @@ -0,0 +1,71 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import jakarta.persistence.Column +import jakarta.persistence.Embeddable +import jakarta.persistence.EmbeddedId +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.MapsId +import jakarta.persistence.Table +import org.hibernate.Hibernate +import java.io.Serializable +import java.util.UUID + +@Entity +@Table(name = "env_actions_control_plan_tags") +class EnvActionsControlPlanTagModel( + @EmbeddedId val id: EnvActionsTagPk, + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("envActionId") + @JoinColumn(name = "env_action_id") + val envAction: EnvActionModel? = null, + @ManyToOne(fetch = FetchType.EAGER) + @MapsId("tagId") + @JoinColumn(name = "tag_id") + val controlPlanTag: ControlPlanTagModel? = null, +) { + companion object { + fun fromEnvActionControlPlanTagEntity( + envAction: EnvActionModel, + controlPlanTag: ControlPlanTagModel, + ) = + EnvActionsControlPlanTagModel( + id = + EnvActionsTagPk( + envActionId = envAction.id!!, + tagId = controlPlanTag.id!!, + ), + envAction = envAction, + controlPlanTag = controlPlanTag, + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as EnvActionsControlPlanTagModel + + return id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} + +@Embeddable +data class EnvActionsTagPk( + @Column(name = "env_action_id") val envActionId: UUID, + @Column(name = "tag_id") val tagId: Int, +) : Serializable { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is EnvActionsTagPk) return false + + return envActionId == other.envActionId && tagId == other.tagId + } + + override fun hashCode(): Int { + return listOf(envActionId, tagId).hashCode() + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanThemeModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanThemeModel.kt new file mode 100644 index 0000000000..a505117f3a --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/EnvActionsControlPlanThemeModel.kt @@ -0,0 +1,77 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import jakarta.persistence.Column +import jakarta.persistence.Embeddable +import jakarta.persistence.EmbeddedId +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.MapsId +import jakarta.persistence.Table +import org.hibernate.Hibernate +import java.io.Serializable +import java.util.UUID + +@Entity +@Table(name = "env_actions_control_plan_themes") +class EnvActionsControlPlanThemeModel( + @EmbeddedId + val id: EnvActionsThemePk, + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("envActionId") + @JoinColumn(name = "env_action_id") + val envAction: EnvActionModel? = null, + + @ManyToOne(fetch = FetchType.EAGER) + @MapsId("themeId") + @JoinColumn(name = "theme_id") + val controlPlanTheme: ControlPlanThemeModel? = null, + +) { + companion object { + fun fromEnvActionControlPlanThemeEntity( + envAction: EnvActionModel, + controlPlanTheme: ControlPlanThemeModel, + ) = EnvActionsControlPlanThemeModel( + id = EnvActionsThemePk( + envActionId = envAction.id!!, + themeId = controlPlanTheme.id!!, + ), + envAction = envAction, + controlPlanTheme = controlPlanTheme, + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as EnvActionsControlPlanThemeModel + + return id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} + +@Embeddable +data class EnvActionsThemePk( + @Column(name = "env_action_id") + val envActionId: UUID, + + @Column(name = "theme_id") + val themeId: Int, +) : Serializable { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is EnvActionsThemePk) return false + + return envActionId == other.envActionId && + themeId == other.themeId + } + + override fun hashCode(): Int { + return listOf(envActionId, themeId).hashCode() + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/MissionModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/MissionModel.kt index e4d3c252a4..ab90aabaeb 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/MissionModel.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/MissionModel.kt @@ -33,39 +33,18 @@ import java.time.ZoneOffset.UTC ) @Entity @Table(name = "missions") -data class MissionModel( +class MissionModel( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id", unique = true, nullable = false) val id: Int? = null, - @Type( - ListArrayType::class, - parameters = [Parameter(name = SQL_ARRAY_TYPE, value = "text")], - ) - @Column(name = "mission_types", columnDefinition = "text[]") - val missionTypes: List, - @Column(name = "open_by") val openBy: String? = null, - @Column(name = "closed_by") val closedBy: String? = null, - @Column(name = "observations_cacem") val observationsCacem: String? = null, - @Column(name = "observations_cnsp") val observationsCnsp: String? = null, - @Column(name = "facade") val facade: String? = null, - @JsonSerialize(using = GeometrySerializer::class) - @JsonDeserialize(contentUsing = GeometryDeserializer::class) - @Column(name = "geom") - val geom: MultiPolygon? = null, - @Column(name = "start_datetime_utc") val startDateTimeUtc: Instant, - @Column(name = "end_datetime_utc") val endDateTimeUtc: Instant? = null, - @Column(name = "closed", nullable = false) val isClosed: Boolean, - @Column(name = "deleted", nullable = false) val isDeleted: Boolean, - @Column(name = "mission_source", nullable = false, columnDefinition = "mission_source_type") - @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType::class) - val missionSource: MissionSourceEnum, - @Column(name = "has_mission_order", nullable = false) val hasMissionOrder: Boolean, - @Column(name = "is_geometry_computed_from_controls", nullable = false) - val isGeometryComputedFromControls: Boolean, - @Column(name = "is_under_jdp", nullable = false) val isUnderJdp: Boolean, + + @OneToMany(mappedBy = "mission") + @JsonManagedReference + @Fetch(value = FetchMode.SUBSELECT) + val attachedReportings: List? = listOf(), + @OneToMany( mappedBy = "mission", cascade = [CascadeType.ALL], @@ -74,7 +53,8 @@ data class MissionModel( ) @JsonManagedReference @Fetch(value = FetchMode.SUBSELECT) - val envActions: MutableList? = ArrayList(), + val controlResources: MutableList? = ArrayList(), + @OneToMany( mappedBy = "mission", cascade = [CascadeType.ALL], @@ -83,7 +63,11 @@ data class MissionModel( ) @JsonManagedReference @Fetch(value = FetchMode.SUBSELECT) - val controlResources: MutableList? = ArrayList(), + val controlUnits: MutableList? = ArrayList(), + + @Column(name = "closed_by") + val closedBy: String? = null, + @OneToMany( mappedBy = "mission", cascade = [CascadeType.ALL], @@ -92,11 +76,58 @@ data class MissionModel( ) @JsonManagedReference @Fetch(value = FetchMode.SUBSELECT) - val controlUnits: MutableList? = ArrayList(), - @OneToMany(mappedBy = "mission") - @JsonManagedReference - @Fetch(value = FetchMode.SUBSELECT) - val attachedReportings: List? = listOf(), + val envActions: MutableList? = ArrayList(), + + @Column(name = "end_datetime_utc") + val endDateTimeUtc: Instant? = null, + + @Column(name = "facade") + val facade: String? = null, + + @JsonSerialize(using = GeometrySerializer::class) + @JsonDeserialize(contentUsing = GeometryDeserializer::class) + @Column(name = "geom") + val geom: MultiPolygon? = null, + + @Column(name = "has_mission_order", nullable = false) + val hasMissionOrder: Boolean, + + @Column(name = "closed", nullable = false) + val isClosed: Boolean, + + @Column(name = "deleted", nullable = false) + val isDeleted: Boolean, + + @Column(name = "is_geometry_computed_from_controls", nullable = false) + val isGeometryComputedFromControls: Boolean, + + @Column(name = "is_under_jdp", nullable = false) + val isUnderJdp: Boolean, + + @Column(name = "mission_source", nullable = false, columnDefinition = "mission_source_type") + @Enumerated(EnumType.STRING) + @Type(PostgreSQLEnumType::class) + val missionSource: MissionSourceEnum, + + @Type( + ListArrayType::class, + parameters = [Parameter(name = SQL_ARRAY_TYPE, value = "text")], + ) + @Column(name = "mission_types", columnDefinition = "text[]") + val missionTypes: List, + + @Column(name = "observations_cacem") + val observationsCacem: String? = null, + + @Column(name = "observations_cnsp") + val observationsCnsp: String? = null, + + @Column(name = "open_by") + val openBy: String? = null, + + @Column(name = "start_datetime_utc") + val startDateTimeUtc: Instant, + ) { fun toMissionEntity(objectMapper: ObjectMapper): MissionEntity { val controlUnits = @@ -116,24 +147,24 @@ data class MissionModel( } return MissionEntity( - id, - missionTypes, - controlUnits, - openBy, - closedBy, - observationsCacem, - observationsCnsp, - facade, - geom, - startDateTimeUtc = startDateTimeUtc.atZone(UTC), + id = id, + closedBy = closedBy, + controlUnits = controlUnits, endDateTimeUtc = endDateTimeUtc?.atZone(UTC), envActions = envActions!!.map { it.toActionEntity(objectMapper) }, - isClosed, - isDeleted, - isGeometryComputedFromControls, - missionSource, - hasMissionOrder, - isUnderJdp, + facade = facade, + geom = geom, + hasMissionOrder = hasMissionOrder, + isClosed = isClosed, + isDeleted = isDeleted, + isGeometryComputedFromControls = isGeometryComputedFromControls, + isUnderJdp = isUnderJdp, + missionSource = missionSource, + missionTypes = missionTypes, + observationsCacem = observationsCacem, + observationsCnsp = observationsCnsp, + openBy = openBy, + startDateTimeUtc = startDateTimeUtc.atZone(UTC), ) } @@ -205,32 +236,42 @@ data class MissionModel( companion object { fun fromMissionEntity( mission: MissionEntity, - mapper: ObjectMapper, controlUnitResourceModelMap: Map, + controlPlanThemesReferenceModelMap: Map, + controlPlanSubThemesReferenceModelMap: Map, + controlPlanTagsReferenceModelMap: Map, + mapper: ObjectMapper, ): MissionModel { val missionModel = MissionModel( id = mission.id, - missionTypes = mission.missionTypes, - openBy = mission.openBy, closedBy = mission.closedBy, - observationsCacem = mission.observationsCacem, - observationsCnsp = mission.observationsCnsp, + endDateTimeUtc = mission.endDateTimeUtc?.toInstant(), facade = mission.facade, geom = mission.geom, - startDateTimeUtc = mission.startDateTimeUtc.toInstant(), - endDateTimeUtc = mission.endDateTimeUtc?.toInstant(), + hasMissionOrder = mission.hasMissionOrder, isClosed = mission.isClosed, isDeleted = false, - missionSource = mission.missionSource, - hasMissionOrder = mission.hasMissionOrder, - isUnderJdp = mission.isUnderJdp, isGeometryComputedFromControls = mission.isGeometryComputedFromControls, + isUnderJdp = mission.isUnderJdp, + missionSource = mission.missionSource, + missionTypes = mission.missionTypes, + observationsCacem = mission.observationsCacem, + observationsCnsp = mission.observationsCnsp, + openBy = mission.openBy, + startDateTimeUtc = mission.startDateTimeUtc.toInstant(), ) mission.envActions?.map { missionModel.envActions?.add( - EnvActionModel.fromEnvActionEntity(it, missionModel, mapper), + EnvActionModel.fromEnvActionEntity( + action = it, + mission = missionModel, + controlPlanThemesReferenceModelMap = controlPlanThemesReferenceModelMap, + controlPlanSubThemesReferenceModelMap = controlPlanSubThemesReferenceModelMap, + controlPlanTagsReferenceModelMap = controlPlanTagsReferenceModelMap, + mapper = mapper, + ), ) } @@ -275,10 +316,4 @@ data class MissionModel( } override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String { - return this::class.simpleName + - "(id = $id , missionTypes = $missionTypes , openBy = $openBy , closedBy = $closedBy , observationsCacem = $observationsCacem, observationsCnsp = $observationsCnsp , facade = $facade , geom = $geom , startDateTimeUtc = $startDateTimeUtc , endDateTimeUtc = $endDateTimeUtc, isClosed = $isClosed, isDeleted = $isDeleted, missionSource = $missionSource )" - } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt index 16597bd60f..c66181189a 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingModel.kt @@ -11,9 +11,9 @@ import fr.gouv.cacem.monitorenv.domain.entities.reporting.SourceTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.reporting.TargetDetailsEntity import fr.gouv.cacem.monitorenv.domain.entities.reporting.TargetTypeEnum import fr.gouv.cacem.monitorenv.domain.use_cases.reportings.dtos.ReportingDTO -import io.hypersistence.utils.hibernate.type.array.ListArrayType import io.hypersistence.utils.hibernate.type.basic.PostgreSQLEnumType import io.hypersistence.utils.hibernate.type.json.JsonBinaryType +import jakarta.persistence.CascadeType import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.EnumType @@ -24,12 +24,13 @@ import jakarta.persistence.GenerationType import jakarta.persistence.Id import jakarta.persistence.JoinColumn import jakarta.persistence.ManyToOne +import jakarta.persistence.OneToMany import jakarta.persistence.Table import org.hibernate.Hibernate import org.hibernate.annotations.Generated -import org.hibernate.annotations.GenerationTime import org.hibernate.annotations.JdbcType import org.hibernate.annotations.Type +import org.hibernate.generator.EventType import org.hibernate.type.descriptor.jdbc.UUIDJdbcType import org.locationtech.jts.geom.Geometry import org.n52.jackson.datatype.jts.GeometryDeserializer @@ -39,12 +40,13 @@ import java.time.ZoneOffset.UTC @Entity @Table(name = "reportings") -data class ReportingModel( +class ReportingModel( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false) val id: Int? = null, - @Generated(GenerationTime.INSERT) + + @Generated(event = [EventType.INSERT]) @Column( name = "reporting_id", unique = true, @@ -57,55 +59,97 @@ data class ReportingModel( @Enumerated(EnumType.STRING) @Type(PostgreSQLEnumType::class) val sourceType: SourceTypeEnum? = null, + @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "semaphore_id", nullable = true) @JsonBackReference val semaphore: SemaphoreModel? = null, + @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "control_unit_id", nullable = true) @JsonBackReference val controlUnit: ControlUnitModel? = null, - @Column(name = "source_name") val sourceName: String? = null, + + @Column(name = "source_name") + val sourceName: String? = null, + @Column(name = "target_type", columnDefinition = "reportings_target_type") @Enumerated(EnumType.STRING) @Type(PostgreSQLEnumType::class) val targetType: TargetTypeEnum? = null, + @Column(name = "vehicle_type", columnDefinition = "reportings_vehicle_type") @Enumerated(EnumType.STRING) @Type(PostgreSQLEnumType::class) val vehicleType: VehicleTypeEnum? = null, + @Column(name = "target_details", columnDefinition = "jsonb") @Type(JsonBinaryType::class) val targetDetails: List? = listOf(), + @JsonSerialize(using = GeometrySerializer::class) @JsonDeserialize(contentUsing = GeometryDeserializer::class) @Column(name = "geom") val geom: Geometry? = null, - @Column(name = "sea_front") val seaFront: String? = null, - @Column(name = "description") val description: String? = null, + + @Column(name = "sea_front") + val seaFront: String? = null, + + @Column(name = "description") + val description: String? = null, + @Column(name = "report_type", columnDefinition = "reportings_report_type") @Enumerated(EnumType.STRING) @Type(PostgreSQLEnumType::class) val reportType: ReportingTypeEnum? = null, - @Column(name = "theme") val theme: String? = null, - @Column(name = "sub_themes") - @Type(ListArrayType::class) - val subThemes: List? = listOf(), - @Column(name = "action_taken") val actionTaken: String? = null, - @Column(name = "is_control_required") val isControlRequired: Boolean? = null, - @Column(name = "has_no_unit_available") val hasNoUnitAvailable: Boolean? = null, - @Column(name = "created_at") val createdAt: Instant, - @Column(name = "validity_time") val validityTime: Int? = null, - @Column(name = "is_archived", nullable = false) val isArchived: Boolean, - @Column(name = "is_deleted", nullable = false) val isDeleted: Boolean, - @Column(name = "open_by") val openBy: String? = null, + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "control_plan_theme_id", nullable = true) + val controlPlanTheme: ControlPlanThemeModel? = null, + + @OneToMany( + fetch = FetchType.EAGER, + cascade = [CascadeType.ALL], + orphanRemoval = true, + mappedBy = "reporting", + ) + val controlPlanSubThemes: MutableList? = ArrayList(), + + @Column(name = "action_taken") + val actionTaken: String? = null, + + @Column(name = "is_control_required") + val isControlRequired: Boolean? = null, + + @Column(name = "has_no_unit_available") + val hasNoUnitAvailable: Boolean? = null, + + @Column(name = "created_at") + val createdAt: Instant, + + @Column(name = "validity_time") + val validityTime: Int? = null, + + @Column(name = "is_archived", nullable = false) + val isArchived: Boolean, + + @Column(name = "is_deleted", nullable = false) + val isDeleted: Boolean, + + @Column(name = "open_by") + val openBy: String? = null, + @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "mission_id", nullable = true) @JsonBackReference val mission: MissionModel? = null, - @Column(name = "attached_to_mission_at_utc") val attachedToMissionAtUtc: Instant? = null, + + @Column(name = "attached_to_mission_at_utc") + val attachedToMissionAtUtc: Instant? = null, + @Column(name = "detached_from_mission_at_utc") val detachedFromMissionAtUtc: Instant? = null, + @JdbcType(UUIDJdbcType::class) @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( @@ -131,8 +175,8 @@ data class ReportingModel( seaFront = seaFront, description = description, reportType = reportType, - theme = theme, - subThemes = subThemes, + themeId = controlPlanTheme?.id, + subThemeIds = controlPlanSubThemes?.map { it.id.subthemeId }, actionTaken = actionTaken, isControlRequired = isControlRequired, hasNoUnitAvailable = hasNoUnitAvailable, @@ -187,35 +231,34 @@ data class ReportingModel( controlUnitReference: ControlUnitModel?, missionReference: MissionModel?, envActionReference: EnvActionModel?, - ) = - ReportingModel( - id = reporting.id, - reportingId = reporting.reportingId, - sourceType = reporting.sourceType, - semaphore = semaphoreReference, - controlUnit = controlUnitReference, - sourceName = reporting.sourceName, - targetType = reporting.targetType, - vehicleType = reporting.vehicleType, - targetDetails = reporting.targetDetails, - geom = reporting.geom, - seaFront = reporting.seaFront, - description = reporting.description, - reportType = reporting.reportType, - theme = reporting.theme, - subThemes = reporting.subThemes, - actionTaken = reporting.actionTaken, - isControlRequired = reporting.isControlRequired, - hasNoUnitAvailable = reporting.hasNoUnitAvailable, - createdAt = reporting.createdAt.toInstant(), - validityTime = reporting.validityTime, - isArchived = reporting.isArchived, - isDeleted = reporting.isDeleted, - openBy = reporting.openBy, - mission = missionReference, - attachedToMissionAtUtc = reporting.attachedToMissionAtUtc?.toInstant(), - detachedFromMissionAtUtc = reporting.detachedFromMissionAtUtc?.toInstant(), - attachedEnvAction = envActionReference, - ) + controlPlanThemeReference: ControlPlanThemeModel?, + ) = ReportingModel( + id = reporting.id, + reportingId = reporting.reportingId, + sourceType = reporting.sourceType, + semaphore = semaphoreReference, + controlUnit = controlUnitReference, + sourceName = reporting.sourceName, + targetType = reporting.targetType, + vehicleType = reporting.vehicleType, + targetDetails = reporting.targetDetails, + geom = reporting.geom, + seaFront = reporting.seaFront, + description = reporting.description, + reportType = reporting.reportType, + controlPlanTheme = controlPlanThemeReference, + actionTaken = reporting.actionTaken, + isControlRequired = reporting.isControlRequired, + hasNoUnitAvailable = reporting.hasNoUnitAvailable, + createdAt = reporting.createdAt.toInstant(), + validityTime = reporting.validityTime, + isArchived = reporting.isArchived, + isDeleted = reporting.isDeleted, + openBy = reporting.openBy, + mission = missionReference, + attachedToMissionAtUtc = reporting.attachedToMissionAtUtc?.toInstant(), + detachedFromMissionAtUtc = reporting.detachedFromMissionAtUtc?.toInstant(), + attachedEnvAction = envActionReference, + ) } } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingsControlPlanSubThemeModel.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingsControlPlanSubThemeModel.kt new file mode 100644 index 0000000000..0245349255 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/model/ReportingsControlPlanSubThemeModel.kt @@ -0,0 +1,73 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.model + +import jakarta.persistence.Column +import jakarta.persistence.Embeddable +import jakarta.persistence.EmbeddedId +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.MapsId +import jakarta.persistence.Table +import org.hibernate.Hibernate +import java.io.Serializable + +@Entity +@Table(name = "reportings_control_plan_sub_themes") +class ReportingsControlPlanSubThemeModel( + @EmbeddedId + val id: ReportingsSubThemePk, + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("reportingId") + @JoinColumn(name = "reporting_id") + val reporting: ReportingModel? = null, + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("subthemeId") + @JoinColumn(name = "subtheme_id") + val controlPlanSubTheme: ControlPlanSubThemeModel? = null, +) { + companion object { + fun fromModels( + reporting: ReportingModel, + controlPlanSubTheme: ControlPlanSubThemeModel, + ) = ReportingsControlPlanSubThemeModel( + id = ReportingsSubThemePk( + reportingId = reporting.id!!, + subthemeId = controlPlanSubTheme.id, + ), + reporting = reporting, + controlPlanSubTheme = controlPlanSubTheme, + ) + } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as ReportingsControlPlanSubThemeModel + + return id != null && id == other.id + } + + override fun hashCode(): Int = javaClass.hashCode() +} + +@Embeddable +data class ReportingsSubThemePk( + @Column(name = "reporting_id") + val reportingId: Int, + @Column(name = "subtheme_id") + val subthemeId: Int, +) : Serializable { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ReportingsSubThemePk) return false + + return reportingId == other.reportingId && + subthemeId == other.subthemeId + } + + override fun hashCode(): Int { + return listOf(reportingId, subthemeId).hashCode() + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanSubThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanSubThemeRepository.kt new file mode 100644 index 0000000000..f73e74ec0f --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanSubThemeRepository.kt @@ -0,0 +1,20 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanSubThemeRepository +import org.springframework.stereotype.Repository + +@Repository +class JpaControlPlanSubThemeRepository( + private val dbControlPlanSubThemeRepository: IDBControlPlanSubThemeRepository, +) : IControlPlanSubThemeRepository { + override fun findAll(): List { + return dbControlPlanSubThemeRepository.findAll().map { it.toControlPlanSubThemeEntity() } + } + override fun findByYear(year: Int): List { + return dbControlPlanSubThemeRepository.findByYearOrderById(year).map { + it.toControlPlanSubThemeEntity() + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanTagRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanTagRepository.kt new file mode 100644 index 0000000000..5da1764cc4 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanTagRepository.kt @@ -0,0 +1,20 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanTagRepository +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanTagRepository +import org.springframework.stereotype.Repository + +@Repository +class JpaControlPlanTagRepository( + private val dbControlPlanTagRepository: IDBControlPlanTagRepository, +) : IControlPlanTagRepository { + override fun findAll(): List { + return dbControlPlanTagRepository.findAll().map { it.toControlPlanTagEntity() } + } + override fun findByYear(year: Int): List { + return dbControlPlanTagRepository.findByYearOrderById(year).map { + it.toControlPlanTagEntity() + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanThemeRepository.kt new file mode 100644 index 0000000000..1826e74a8d --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanThemeRepository.kt @@ -0,0 +1,20 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories + +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanThemeRepository +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanThemeRepository +import org.springframework.stereotype.Repository + +@Repository +class JpaControlPlanThemeRepository( + private val dbControlPlanThemeRepository: IDBControlPlanThemeRepository, +) : IControlPlanThemeRepository { + override fun findAll(): List { + return dbControlPlanThemeRepository.findAll().map { it.toControlPlanThemeEntity() } + } + override fun findByYear(year: Int): List { + return dbControlPlanThemeRepository.findByYearOrderById(year).map { + it.toControlPlanThemeEntity() + } + } +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlThemeRepository.kt index 66eb9385c0..be90d2af1d 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlThemeRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlThemeRepository.kt @@ -5,6 +5,7 @@ import fr.gouv.cacem.monitorenv.domain.repositories.IControlThemeRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlThemeRepository import org.springframework.stereotype.Repository +@Deprecated("Use JpaControlPlanSubThemeRepository instead") @Repository class JpaControlThemeRepository(private val dbControlThemeRepository: IDBControlThemeRepository) : IControlThemeRepository { diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepository.kt index 8eb0d387d8..b824c09ffc 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepository.kt @@ -6,6 +6,9 @@ import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum import fr.gouv.cacem.monitorenv.domain.repositories.IMissionRepository import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.MissionDTO import fr.gouv.cacem.monitorenv.infrastructure.database.model.MissionModel +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanTagRepository +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanThemeRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlUnitResourceRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBMissionRepository import org.springframework.data.domain.Pageable @@ -16,6 +19,9 @@ import java.time.Instant @Repository class JpaMissionRepository( + private val dbControlPlanThemeRepository: IDBControlPlanThemeRepository, + private val dbControlPlanSubThemeRepository: IDBControlPlanSubThemeRepository, + private val dbControlPlanTagRepository: IDBControlPlanTagRepository, private val dbControlUnitResourceRepository: IDBControlUnitResourceRepository, private val dbMissionRepository: IDBMissionRepository, private val mapper: ObjectMapper, @@ -102,16 +108,59 @@ class JpaMissionRepository( @Modifying(clearAutomatically = true, flushAutomatically = true) override fun save(mission: MissionEntity): MissionDTO { // Extract all control units resources unique control unit resource IDs - val uniqueControlUnitResourceIds = mission.controlUnits - .flatMap { controlUnit -> controlUnit.resources.map { it.id } } - .distinct() + val uniqueControlUnitResourceIds = + mission.controlUnits + .flatMap { controlUnit -> controlUnit.resources.map { it.id } } + .distinct() // Fetch all of them as models - val controlUnitResourceModels = dbControlUnitResourceRepository.findAllById(uniqueControlUnitResourceIds) + val controlUnitResourceModels = + dbControlUnitResourceRepository.findAllById(uniqueControlUnitResourceIds) // Create an `[id] → ControlUnitResourceModel` map - val controlUnitResourceModelMap = controlUnitResourceModels.associateBy { requireNotNull(it.id) } + val controlUnitResourceModelMap = + controlUnitResourceModels.associateBy { requireNotNull(it.id) } - val missionModel = MissionModel.fromMissionEntity(mission, mapper, controlUnitResourceModelMap) + val controlPlanThemes = ArrayList() + val controlPlanSubThemes = ArrayList() + val controlPlanTags = ArrayList() + for (envAction in mission.envActions ?: emptyList()) { + for (controlPlan in envAction.controlPlans ?: emptyList()) { + // get a list of all controlPlanTheme ids used in the mission's envActions + controlPlanThemes.add(controlPlan.themeId ?: continue) + // get a list of all controlPlanSubThemes ids used in the mission's envActions + controlPlanSubThemes.addAll(controlPlan.subThemeIds ?: emptyList()) + // get a list of all controlPlanTags ids used in the mission's envActions + controlPlanTags.addAll(controlPlan.tagIds ?: emptyList()) + } + } + + // Create a map from controlPlanThemes mapping each id to a reference to the model + val controlPlanThemesReferenceModelMap = + controlPlanThemes?.distinct()?.associateWith { id -> + dbControlPlanThemeRepository.getReferenceById(id) + } + // Create a map from controlPlanSubThemes mapping each id to a reference to the model + val controlPlanSubThemesReferenceModelMap = + controlPlanSubThemes?.distinct()?.associateWith { id -> + dbControlPlanSubThemeRepository.getReferenceById(id) + } + // Create a map from controlPlanTags mapping each id to a reference to the model + val controlPlanTagsReferenceModelMap = + controlPlanTags?.distinct()?.associateWith { id -> + dbControlPlanTagRepository.getReferenceById(id) + } + val missionModel = + MissionModel.fromMissionEntity( + mission = mission, + controlUnitResourceModelMap = controlUnitResourceModelMap, + controlPlanThemesReferenceModelMap = controlPlanThemesReferenceModelMap + ?: emptyMap(), + controlPlanSubThemesReferenceModelMap = + controlPlanSubThemesReferenceModelMap ?: emptyMap(), + controlPlanTagsReferenceModelMap = controlPlanTagsReferenceModelMap + ?: emptyMap(), + mapper = mapper, + ) return dbMissionRepository.saveAndFlush(missionModel).toMissionDTO(mapper) } diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt index fa0f22cfa7..f8f84cf0b6 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepository.kt @@ -8,6 +8,9 @@ import fr.gouv.cacem.monitorenv.domain.exceptions.NotFoundException import fr.gouv.cacem.monitorenv.domain.repositories.IReportingRepository import fr.gouv.cacem.monitorenv.domain.use_cases.reportings.dtos.ReportingDTO import fr.gouv.cacem.monitorenv.infrastructure.database.model.ReportingModel +import fr.gouv.cacem.monitorenv.infrastructure.database.model.ReportingsControlPlanSubThemeModel +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlPlanThemeRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBControlUnitRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBEnvActionRepository import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces.IDBMissionRepository @@ -27,6 +30,8 @@ class JpaReportingRepository( private val dbReportingRepository: IDBReportingRepository, private val dbMissionRepository: IDBMissionRepository, private val dbSemaphoreRepository: IDBSemaphoreRepository, + private val dbControlPlanThemeRepository: IDBControlPlanThemeRepository, + private val dbControlPlanSubThemeRepository: IDBControlPlanSubThemeRepository, private val dbControlUnitRepository: IDBControlUnitRepository, private val dbEnvActionRepository: IDBEnvActionRepository, private val mapper: ObjectMapper, @@ -118,15 +123,56 @@ class JpaReportingRepository( } else { null } - val reportingModel = - ReportingModel.fromReportingEntity( - reporting = reporting, - semaphoreReference = semaphoreReference, - controlUnitReference = controlUnitReference, - missionReference = missionReference, - envActionReference = envActionReference, - ) + val controlPlanThemeReference = + if (reporting.themeId != null) { + dbControlPlanThemeRepository.getReferenceById( + reporting.themeId, + ) + } else { + null + } + val controlPlanSubThemesReferenceList = + reporting.subThemeIds?.map { + dbControlPlanSubThemeRepository.getReferenceById(it) + } + // To save controlPlanSubThemes we must ensure that reportingId is set + // to simplify the understandability of the code, we do the same steps for creation and + // update + // even if it is not necessary for update + // first save (ensure id is set) + val reportingModel: ReportingModel + + if (reporting.id == null) { + reportingModel = + dbReportingRepository.save( + ReportingModel.fromReportingEntity( + reporting = reporting, + semaphoreReference = semaphoreReference, + controlUnitReference = controlUnitReference, + missionReference = missionReference, + envActionReference = envActionReference, + controlPlanThemeReference = controlPlanThemeReference, + ), + ) + } else { + reportingModel = + ReportingModel.fromReportingEntity( + reporting = reporting, + semaphoreReference = semaphoreReference, + controlUnitReference = controlUnitReference, + missionReference = missionReference, + envActionReference = envActionReference, + controlPlanThemeReference = controlPlanThemeReference, + ) + } + + // set controlPlanSubThemes and save again (and flush) + controlPlanSubThemesReferenceList?.forEach { it -> + reportingModel.controlPlanSubThemes?.add( + ReportingsControlPlanSubThemeModel.fromModels(reportingModel, it), + ) + } dbReportingRepository.saveAndFlush(reportingModel).toReportingDTO(mapper) } catch (e: JpaObjectRetrievalFailureException) { throw NotFoundException( diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanSubThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanSubThemeRepository.kt new file mode 100644 index 0000000000..21fad8c5ec --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanSubThemeRepository.kt @@ -0,0 +1,8 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces + +import fr.gouv.cacem.monitorenv.infrastructure.database.model.ControlPlanSubThemeModel +import org.springframework.data.jpa.repository.JpaRepository + +interface IDBControlPlanSubThemeRepository : JpaRepository { + fun findByYearOrderById(year: Int): List +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanTagRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanTagRepository.kt new file mode 100644 index 0000000000..371bed3fcc --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanTagRepository.kt @@ -0,0 +1,22 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces + +import fr.gouv.cacem.monitorenv.infrastructure.database.model.ControlPlanTagModel +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface IDBControlPlanTagRepository : JpaRepository { + + @Query( + value = + """ + SELECT tags.* + FROM control_plan_tags tags, control_plan_sub_themes s, control_plan_themes th + WHERE tags.theme_id = th.id + AND th.id = s.theme_id + AND s.year = :year + ORDER BY tags.id ASC + """, + nativeQuery = true, + ) + fun findByYearOrderById(year: Int): List +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanThemeRepository.kt new file mode 100644 index 0000000000..f3bd070af7 --- /dev/null +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlPlanThemeRepository.kt @@ -0,0 +1,19 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces + +import fr.gouv.cacem.monitorenv.infrastructure.database.model.ControlPlanThemeModel +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface IDBControlPlanThemeRepository : JpaRepository { + @Query( + value = """ + SELECT th.* + FROM control_plan_themes th, control_plan_sub_themes s + WHERE th.id = s.theme_id + AND s.year = :year + ORDER BY th.id ASC + """, + nativeQuery = true, + ) + fun findByYearOrderById(year: Int): List +} diff --git a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlThemeRepository.kt b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlThemeRepository.kt index 7447f1faec..f31d355bce 100644 --- a/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlThemeRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/interfaces/IDBControlThemeRepository.kt @@ -3,4 +3,5 @@ package fr.gouv.cacem.monitorenv.infrastructure.database.repositories.interfaces import fr.gouv.cacem.monitorenv.infrastructure.database.model.ControlThemeModel import org.springframework.data.repository.CrudRepository +@Deprecated("Use IDBControlPlanSubThemeRepository instead") interface IDBControlThemeRepository : CrudRepository diff --git a/backend/src/main/resources/db/migration/internal/V0.103__create_action_theme.sql b/backend/src/main/resources/db/migration/internal/V0.103__create_action_theme.sql new file mode 100644 index 0000000000..52c97e821d --- /dev/null +++ b/backend/src/main/resources/db/migration/internal/V0.103__create_action_theme.sql @@ -0,0 +1,169 @@ +-- Création des tables + +CREATE TABLE control_plan_themes ( + id serial PRIMARY KEY, + theme text UNIQUE NOT NULL +); + +CREATE TABLE control_plan_sub_themes ( + id serial PRIMARY KEY, + subtheme text, + theme_id int REFERENCES control_plan_themes(id), + year int +); +CREATE INDEX idx_control_plan_sub_themes_year ON control_plan_sub_themes USING btree(year); + + +CREATE TABLE control_plan_tags ( + id serial PRIMARY KEY, + tag text, + theme_id int REFERENCES control_plan_themes(id) +); + +CREATE TABLE env_actions_control_plan_themes ( + env_action_id uuid, + theme_id integer NOT NULL, + foreign key (env_action_id) references env_actions(id), + foreign key (theme_id) references control_plan_themes(id), + primary key (env_action_id, theme_id) +); + +CREATE TABLE env_actions_control_plan_sub_themes ( + env_action_id uuid, + subtheme_id integer, + foreign key (env_action_id) references env_actions(id), + foreign key (subtheme_id) references control_plan_sub_themes(id), + primary key (env_action_id, subtheme_id) +); + +CREATE TABLE env_actions_control_plan_tags ( + env_action_id uuid, + tag_id integer, + foreign key (env_action_id) references env_actions(id), + foreign key (tag_id) references control_plan_tags(id), + primary key (env_action_id, tag_id) +); + +CREATE TABLE reportings_control_plan_sub_themes ( + reporting_id integer, + subtheme_id integer, + foreign key (reporting_id) references reportings(id), + foreign key (subtheme_id) references control_plan_sub_themes(id), + primary key (reporting_id, subtheme_id) +); + +COMMENT ON TABLE reportings_control_plan_sub_themes IS 'Table de jointure entre les signalements et les sous-thèmes du plan de contrôle'; +COMMENT ON TABLE control_plan_themes IS 'Table des thèmes du plan de contrôle'; +COMMENT ON TABLE control_plan_sub_themes IS 'Table des sous-thèmes du plan de contrôle versionnés par année'; +COMMENT ON TABLE control_plan_tags IS 'Table des tags du plan de contrôle reliés aux thématiques'; +COMMENT ON TABLE env_actions_control_plan_sub_themes IS 'Table de jointure entre les actions et les sous-thèmes du plan de contrôle'; +COMMENT ON TABLE env_actions_control_plan_tags IS 'Table de jointure entre les actions et les tags reliées aux thématiques du plan de contrôle'; + +ALTER TABLE reportings add column control_plan_theme_id integer; +ALTER TABLE reportings ADD CONSTRAINT fk_reportings_control_plan_themes FOREIGN KEY (control_plan_theme_id) REFERENCES control_plan_themes(id); + +-- Insertion des themes et sous-themes à partir de la table control_themes +INSERT INTO control_plan_themes (theme) + SELECT distinct theme_level_1 FROM control_themes ORDER BY theme_level_1 + ; + +INSERT INTO control_plan_sub_themes (subtheme, theme_id, year) + SELECT distinct theme_level_2, t.id, 2023 + FROM control_themes c JOIN control_plan_themes t ON t.theme = theme_level_1 + WHERE theme_level_2 IS NOT NULL ORDER BY theme_level_2 +; + +INSERT INTO control_plan_tags (theme_id, tag) + SELECT t.id, unnest(ARRAY['Oiseaux', 'Habitat', 'Flore', 'Autres espèces protégées', 'Reptiles', 'Mammifères marins']) + FROM control_plan_themes t + WHERE t.theme = 'Police des espèces protégées et de leurs habitats (faune et flore)' +; + +-- EnvActions: Insertion des données depuis les env actions dans la table env_actions_control_plan_themes +INSERT INTO env_actions_control_plan_themes (env_action_id, theme_id) + WITH themes AS ( + SELECT + id as env_action_id, + jsonb_array_elements(value->'themes')->>'theme' as theme + FROM env_actions + WHERE value->>'themes' is not null + ) + SELECT DISTINCT themes.env_action_id, th.id + FROM themes, + control_plan_themes th + WHERE th.theme = themes.theme +; +-- EnvActions: Insertion des données depuis les env actions dans la table env_actions_control_plan_sub_themes +INSERT INTO env_actions_control_plan_sub_themes (env_action_id, subtheme_id) + WITH themes AS ( + SELECT + id as env_action_id, + jsonb_array_elements(value->'themes')->>'theme' as theme, + jsonb_array_elements_text(jsonb_array_elements(value->'themes')->'subThemes') as subtheme + FROM env_actions + WHERE value->>'themes' is not null + ) + SELECT DISTINCT themes.env_action_id, sbt.id + FROM themes, + control_plan_sub_themes sbt, + control_plan_themes th + WHERE sbt.subtheme = themes.subtheme + AND sbt.theme_id = th.id + AND th.theme = themes.theme + AND sbt.year = 2023; + +-- EnvActions: Insertion des données depuis les env actions dans la table env_actions_control_plan_tags +INSERT INTO env_actions_control_plan_tags (env_action_id, tag_id) +WITH themes AS ( + SELECT + id as env_action_id, + jsonb_array_elements(value->'themes')->>'theme' as theme, + jsonb_array_elements(value->'themes')->>'protectedSpecies' as protectedspeciestext, + jsonb_array_elements(value->'themes')->'protectedSpecies' as protectedspecies + FROM env_actions + WHERE value->>'themes' is not null +) + SELECT DISTINCT themes.env_action_id, control_plan_tags.id + FROM themes, + LATERAL ( + SELECT + CASE species + WHEN 'BIRDS' THEN 'Oiseaux' + WHEN 'HABITAT' THEN 'Habitat' + WHEN 'FLORA' THEN 'Flore' + WHEN 'OTHER' THEN 'Autres espèces protégées' + WHEN 'REPTILES' THEN 'Reptiles' + WHEN 'MARINE_MAMMALS' THEN 'Mammifères marins' + ELSE 'Non défini' + END + FROM (SELECT jsonb_array_elements_text(protectedspecies) species) t + ) d(tags), + control_plan_tags + WHERE control_plan_tags.tag = d.tags + AND protectedspeciestext IS NOT NULL + AND protectedspeciestext !='[]'; + + +--- Signalements +INSERT INTO reportings_control_plan_sub_themes (reporting_id, subtheme_id) + WITH reportingthemes AS ( + SELECT id, + theme, + unnest(sub_themes) as subtheme + FROM public.reportings r + WHERE r.sub_themes is not null + ) + SELECT rt.id, sbt.id + FROM reportingthemes rt, + public.control_plan_themes as th, + public.control_plan_sub_themes as sbt + WHERE th.id = sbt.theme_id + AND rt.theme = th.theme + AND rt.subtheme = sbt.subtheme + AND sbt.year = 2023 +; + +UPDATE reportings + SET control_plan_theme_id = th.id + FROM control_plan_themes as th + WHERE th.theme = reportings.theme; diff --git a/backend/src/main/resources/db/migration/internal/V0.104__update_materialized_view_themes.sql b/backend/src/main/resources/db/migration/internal/V0.104__update_materialized_view_themes.sql new file mode 100644 index 0000000000..f60c242855 --- /dev/null +++ b/backend/src/main/resources/db/migration/internal/V0.104__update_materialized_view_themes.sql @@ -0,0 +1,66 @@ +DROP MATERIALIZED VIEW analytics_actions; + +CREATE MATERIALIZED VIEW public.analytics_actions AS + +SELECT + a.id, + a.mission_id, + action_start_datetime_utc, + action_end_datetime_utc, + EXTRACT(year FROM action_start_datetime_utc) AS year, + m.start_datetime_utc AS mission_start_datetime_utc, + m.end_datetime_utc AS mission_end_datetime_utc, + mission_type, + action_type, + COALESCE(m.facade, 'Hors façade') AS mission_facade, + cu.name AS control_unit, + adm.name AS administration, + cu.name ILIKE 'ulam%' OR ( + adm.name = 'DIRM / DM' AND + cu.name ILIKE 'PAM%' + ) AS is_aff_mar, + ( + cu.name ILIKE 'ulam%' OR ( + adm.name = 'DIRM / DM' AND + cu.name ILIKE 'PAM%' + ) + ) OR adm.name IN ('Gendarmerie Nationale', 'Gendarmerie Maritime', 'Douane', 'Marine Nationale') AS is_aem, + CASE + WHEN cu.name ILIKE 'ulam%' OR (adm.name = 'DIRM / DM' AND cu.name ILIKE 'PAM%') THEN 'Affaires Maritimes' + WHEN adm.name IN ('Gendarmerie Nationale', 'Gendarmerie Maritime', 'Douane', 'Marine Nationale') THEN adm.name + ELSE 'Administrations hors AEM' + END AS administration_aem, + COALESCE(a.facade, 'Hors façade') AS action_facade, + COALESCE(a.department, 'Hors département') AS action_department, + COALESCE(t3.theme, 'Aucun thème') AS theme_level_1, + COALESCE(t2.subtheme, 'Aucun sous-thème') AS theme_level_2, + CASE WHEN action_type = 'CONTROL' THEN ST_X(geom_element.geom) END AS longitude, + CASE WHEN action_type = 'CONTROL' THEN ST_Y(geom_element.geom) END AS latitude, + CASE WHEN action_type = 'CONTROL' THEN CASE WHEN jsonb_array_length(a.value->'infractions') > 0 THEN true ELSE false END END AS infraction, + (a.value->>'actionNumberOfControls')::DOUBLE PRECISION AS number_of_controls, + CASE WHEN action_type = 'SURVEILLANCE' THEN EXTRACT(epoch FROM a.action_end_datetime_utc - a.action_start_datetime_utc) / 3600.0 END AS surveillance_duration, + m.observations_cacem +FROM env_actions a +LEFT JOIN ST_Dump(a.geom) AS geom_element +ON true +LEFT JOIN env_actions_control_plan_sub_themes t1 on t1.env_action_id = a.id +LEFT JOIN control_plan_sub_themes t2 on t2.id = t1.subtheme_id +LEFT JOIN control_plan_themes t3 on t3.id = t2.theme_id +JOIN missions m +ON a.mission_id = m.id +LEFT JOIN LATERAL unnest(mission_types) mission_type ON true +LEFT JOIN missions_control_units mcu +ON mcu.mission_id = m.id +LEFT JOIN control_units cu +ON cu.id = mcu.control_unit_id +LEFT JOIN administrations adm +ON adm.id = cu.administration_id +WHERE + NOT m.deleted AND + m.closed AND + action_type IN ('CONTROL', 'SURVEILLANCE') +ORDER BY action_start_datetime_utc DESC; + +CREATE INDEX ON analytics_actions USING BRIN(action_start_datetime_utc); + +REFRESH MATERIALIZED VIEW public.analytics_actions; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/internal/V0.105__add_control_plan_2024.sql b/backend/src/main/resources/db/migration/internal/V0.105__add_control_plan_2024.sql new file mode 100644 index 0000000000..a7161037f1 --- /dev/null +++ b/backend/src/main/resources/db/migration/internal/V0.105__add_control_plan_2024.sql @@ -0,0 +1,162 @@ +INSERT INTO control_plan_themes (id, theme) VALUES +(100,'Mouillage individuel'), +(101,'Zone de mouillage et d''équipement léger (ZMEL)'), +(102,'Rejet'), +(103,'Espèce protégée et leur habitat (faune et flore)'), +(104,'Bien culturel maritime'), +(105,'Épave'), +(106,'Domanialité publique (circulation et dégradation)'), +(107,'Culture marine'), +(108,'Parc national'), +(109,'Réserve naturelle'), +(110,'Arrêté de protection'), +(111,'Autres'), +(112,'Pêche de loisir (autre que PAP)'), +(113,'Surveillance générale'); + +-- Thématiques existantes pour lesquels une recherche doit être faite pour récupérer l'identifiant +-- Activité et manifestation soumises à évaluation d’incidence Natura 2000 +-- Travaux en milieu marin +-- Arrêté à visa environnemental +-- Pêche à pied + +SELECT setval('control_plan_themes_id_seq', (SELECT max(id) FROM control_plan_themes), true); + +INSERT INTO control_plan_tags (id,theme_id,tag) VALUES +(10,103,'Mammifères marins'), +(11,103,'Oiseaux'), +(12,103,'Reptiles'), +(13,103,'Poissons'), +(14,103,'Flore'), +(15,103,'Habitat'), +(16,103,'Autres espèces protégées'); + +INSERT INTO control_plan_tags (id,tag,theme_id) + SELECT new_tags.*, existing_theme.id FROM (VALUES + (17,'Bichique'), + (18,'Civelle'), + (19,'Filet fixe'), + (20,'Autre')) as new_tags, + ( + SELECT id FROM control_plan_themes + WHERE theme = 'Pêche à pied') existing_theme; + +SELECT setval('control_plan_tags_id_seq', (SELECT max(id) FROM control_plan_tags), true); + + +INSERT INTO control_plan_sub_themes (id,theme_id,subtheme,year) VALUES +(100,100,'Mouillage réglementé par arrêté',2024), +(101,100,'Mouillage réglementé par AMP',2024), +(102,100,'Mouillage avec AOT individuelle',2024), +(103,100,'Autre mouillage individuel',2024), +(104,101,'Gestionnaire ZMEL',2024), +(105,101,'Usagers ZMEL',2024), +(106,101,'Autre (ZMEL)',2024), +(107,102,'Jet de déchet (macro déchet)',2024), +(108,102,'Carénage sauvage',2024), +(109,102,'Rejet d''eau grise / eau noire',2024), +(110,102,'Rejet d''hydrocarbure',2024), +(111,102,'Eaux de ballast',2024), +(112,102,'Pollutions associées aux opérations d''exploration, d''exploitation, d''immersion et d''incinération',2024), +(113,102,'Rejets atmosphériques ',2024), +(114,102,'Avitaillement, soutage, transbordement',2024), +(115,102,'Rejet réglementé par AMP',2024), +(116,102,'Autre rejet',2024), +(117,103,'Destruction, capture, arrachage d''espèces protégées',2024), +(118,103,'Atteinte aux habitats d''espèces protégées',2024), +(119,103,'Transport, vente, exportation, commerce d''espèces protégées',2024), +(120,103,'Détention des espèces protégées',2024), +(121,103,'Dérogations relatives aux espèces protégées et aux habitats d''espèces protégées',2024), +(122,103,'Dérangement / perturbation intentionnelle des espèces animales protégées',2024), +(123,103,'Autre (Espèce protégée et leur habitat)',2024), +(124,104,'Prospection d''un bien culturel maritime',2024), +(125,104,'Aliénation/acquisition d''un bien culturel maritime',2024), +(126,104,'Déplacement/prélèvement/atteinte d''un bien culturel maritime',2024), +(127,104,'Autre (Bien culturel maritime)',2024), +(128,105,'Découverte d''une épave maritime',2024), +(129,105,'Recel ou détournement d''une épave maritime',2024), +(130,105,'Épave / Navire abandonné',2024), +(131,105,'Autre (Épave)',2024), +(137,106,'Circulation des VTM sur le DPM',2024), +(138,106,'Respect des espaces balisés',2024), +(139,106,'Dégradation du DPM',2024), +(140,106,'Autre (DPM)',2024), +(141,107,'Prescriptions réglementaires des concessions d''exploitation de culture marine',2024), +(142,107,'Remise en état après occupation du DPM',2024), +(143,107,'Implantation',2024), +(144,107,'Autre (Culture marine)',2024), +(156,108,'Réglementation du parc national',2024), +(157,108,'Autre (Parc national)',2024), +(158,109,'Réglementation de la réserve naturelle',2024), +(159,109,'Autre (Réserve naturelle)',2024), +(160,110,'Réglementation de l''arrêté de protection',2024), +(161,110,'Autre (Arrêté de protection)',2024), +(162,111,'Drone',2024), +(163,111,'Introduction d''espèce dans le milieu naturel ',2024), +(164,111,'Dérogation d''introduction d''espèce',2024), +(165,111,'Campagnes scientifiques',2024), +(166,111,'Manifestation sur le DPM avec prescriptions environnementales',2024), +(167,111,'Chasse sur le DPM',2024), +(168,111,'Autre',2024), +(173,112,'Pêche embarquée',2024), +(174,112,'Pêche sous-marine',2024), +(175,112,'Engin non-marqué',2024), +(176,112,'Autre (Pêche de loisir hors PAP)',2024), +(177,113,'Surveillance générale',2024) +; + + +INSERT INTO control_plan_sub_themes (id,subtheme,year,theme_id) + SELECT new_sub_themes.*, existing_theme.id FROM (VALUES + (132,'Existence d''une évaluation d''incidence Natura 2000',2024), + (133,'Prescriptions environnementales des manifestations / activités dans une zone Natura 2000',2024), + (134,'Travaux dans une zone Natura 2000',2024), + (135,'Charte Natura 2000',2024), + (136,'Autre (EIN2000)',2024)) as new_sub_themes, + ( + SELECT id FROM control_plan_themes + WHERE theme = 'Activités et manifestations soumises à évaluation d’incidence Natura 2000') existing_theme +; + + +INSERT INTO control_plan_sub_themes (id,subtheme,year,theme_id) + SELECT new_sub_themes.*, existing_theme.id FROM (VALUES + (145,'Dragage',2024), + (146,'Clapage',2024), + (147,'Extraction de granulats ',2024), + (148,'Chantier marin',2024), + (149,'Chantier portuaire',2024), + (150,'Travaux réglementés par AMP',2024), + (151,'Autres travaux en mer',2024)) as new_sub_themes, + ( + SELECT id FROM control_plan_themes + WHERE theme = 'Travaux en milieu marin') existing_theme +; + + +INSERT INTO control_plan_sub_themes (id,subtheme,year,theme_id) + SELECT new_sub_themes.*, existing_theme.id FROM (VALUES + (152,'Arrêtés municipaux réglementant certaines activités avec un impact sur l''environnement marin ',2024), + (153,'Arrêtés du préfet de département réglementant certaines activités avec un impact sur l''environnement marin',2024), + (154,'Arrêtés du préfet maritime réglementant certaines activités avec un impact sur l''environnement marin ',2024), + (155,'Autres arrêtés réglementant certaines activités avec un impact sur l''environnement marin ',2024) +) as new_sub_themes, + ( + SELECT id FROM control_plan_themes + WHERE theme = 'Arrêté à visa environnemental') existing_theme +; + +INSERT INTO control_plan_sub_themes (id,subtheme,year,theme_id) + SELECT new_sub_themes.*, existing_theme.id FROM (VALUES + (169,'Pêche à pied de loisir',2024), + (170,'Pêche à pied professionnelle',2024), + (171,'Engin non-marqué',2024), + (172,'Autre (Pêche à pied)',2024) +) as new_sub_themes, + ( + SELECT id FROM control_plan_themes + WHERE theme = 'Pêche à pied') existing_theme +; + + +SELECT setval('control_plan_sub_themes_id_seq', (SELECT max(id) FROM control_plan_sub_themes), true); \ No newline at end of file diff --git a/backend/src/main/resources/db/testdata/V666.7__insert_facade_areas.sql b/backend/src/main/resources/db/testdata/V666.01__insert_facade_areas.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.7__insert_facade_areas.sql rename to backend/src/main/resources/db/testdata/V666.01__insert_facade_areas.sql diff --git a/backend/src/main/resources/db/testdata/V666.8__dummy_amp_cacem.sql b/backend/src/main/resources/db/testdata/V666.02__dummy_amp_cacem.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.8__dummy_amp_cacem.sql rename to backend/src/main/resources/db/testdata/V666.02__dummy_amp_cacem.sql diff --git a/backend/src/main/resources/db/testdata/V666.2__insert_dummy_regulations_cacem.sql b/backend/src/main/resources/db/testdata/V666.03__insert_dummy_regulations_cacem.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.2__insert_dummy_regulations_cacem.sql rename to backend/src/main/resources/db/testdata/V666.03__insert_dummy_regulations_cacem.sql diff --git a/backend/src/main/resources/db/testdata/V666.10__insert_dummy_department_areas.sql b/backend/src/main/resources/db/testdata/V666.04__insert_dummy_department_areas.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.10__insert_dummy_department_areas.sql rename to backend/src/main/resources/db/testdata/V666.04__insert_dummy_department_areas.sql diff --git a/backend/src/main/resources/db/testdata/V666.3__insert_dummy_bases.sql b/backend/src/main/resources/db/testdata/V666.05__insert_dummy_bases.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.3__insert_dummy_bases.sql rename to backend/src/main/resources/db/testdata/V666.05__insert_dummy_bases.sql diff --git a/backend/src/main/resources/db/testdata/V666.1__insert_dummy_administrations.sql b/backend/src/main/resources/db/testdata/V666.06__insert_dummy_administrations.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.1__insert_dummy_administrations.sql rename to backend/src/main/resources/db/testdata/V666.06__insert_dummy_administrations.sql diff --git a/backend/src/main/resources/db/testdata/V666.4__insert_dummy_control_units.sql b/backend/src/main/resources/db/testdata/V666.07__insert_dummy_control_units.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.4__insert_dummy_control_units.sql rename to backend/src/main/resources/db/testdata/V666.07__insert_dummy_control_units.sql diff --git a/backend/src/main/resources/db/testdata/V666.09__insert_dummy_missions.sql b/backend/src/main/resources/db/testdata/V666.09__insert_dummy_missions.sql new file mode 100644 index 0000000000..cf7ff7ffc8 --- /dev/null +++ b/backend/src/main/resources/db/testdata/V666.09__insert_dummy_missions.sql @@ -0,0 +1,161 @@ +TRUNCATE public.missions CASCADE; + +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types, is_under_jdp) VALUES (50, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'Guadeloupe', '2022-05-11 03:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'CHA', false, NULL, 'MONITORFISH', false, NULL, '{SEA}', true); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (51, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'MEMN', '2022-05-11 04:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'CHA', false, NULL, 'POSEIDON_CACEM', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (52, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'MEMN', '2022-05-11 05:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'CHA', false, NULL, 'POSEIDON_CNSP', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (12, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'NAMO', '2022-02-24 10:56:33', '2022-05-06 19:38:29', NULL, 'CHA', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (13, 'TYL', 'Receive hit themselves. Example community suggest seek to technology.', 'NAMO', '2022-02-07 04:16:43', '2022-07-10 19:55:50', NULL, 'ROB', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (19, 'SCO', 'Difficult ahead let really old around. Cover operation seven surface use show. Manage beautiful reason account prepare evening sure.', 'NAMO', '2022-06-21 13:24:04', '2022-07-18 02:49:08', NULL, 'EDW', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (20, 'CAS', 'South add memory sing population. Entire particularly deep yard avoid. According cell reason entire group accept.', 'MED', '2022-06-18 08:08:01', '2022-08-09 02:29:02', NULL, 'SAR', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (10, 'KIM', 'Remain vote several ok. Bring American play woman challenge. Throw low law positive seven.', 'NAMO', '2022-03-21 12:11:13', NULL, '0106000020E610000001000000010300000001000000050000008AA293E7F23112C0EBC80D961C274840494ABC342C3312C0C127CE382A27484000F63C452F3312C077C8A4F151274840A51B17C4F63112C0B998F263442748408AA293E7F23112C0EBC80D961C274840', 'TRA', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (0, 'LOR', 'Worker smile spend parent certain tell dream. Small hope professor thus. Every nothing rest myself.', 'MED', '2022-05-10 12:23:59', NULL, NULL, 'KYL', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (14, 'MRS', 'Laugh surface few military current fine set. Wife list culture.', 'SA', '2022-03-12 03:48:14', '2022-05-15 03:13:36', NULL, 'MIC', false, NULL, 'MONITORENV', true, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (15, 'KAT', 'Population source pass recognize a modern. Might board take both century.', 'MEMN', '2022-01-21 18:52:58', '2022-02-20 20:37:16', NULL, 'AND', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (16, 'KAI', 'All serve try turn impact society.', 'SA', '2022-05-18 15:16:38', '2022-06-08 01:38:04', NULL, 'CAS', false, NULL, 'MONITORENV', true, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (17, 'KEL', 'Role from six under reveal. Suddenly surface give out. Doctor religious protect.', 'MED', '2022-06-08 02:30:39', '2022-08-06 08:55:19', NULL, 'GER', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (18, 'KEN', 'Upon specific director threat. Picture about some develop its Democrat. Anyone politics whatever morning program debate. Network your fear unit author stop.', 'SA', '2022-03-07 15:51:24', '2022-04-08 15:52:44', NULL, 'NIC', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (22, 'MAR', 'So maintain focus bag. Benefit put charge shake high national experience music. Surface computer decade happen small.', 'SA', '2022-03-24 15:31:07.588693', '2022-07-23 15:02:17.588693', '0106000020E61000000100000001030000000100000004000000ECDC6E9DB53710C0044FC86E756248405F4F142E01E80FC0BCE54742B4624840D6A83C6137F30FC060DA35A9045D4840ECDC6E9DB53710C0044FC86E75624840', 'CAL', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (28, 'TRO', 'Industry term former scene increase miss beyond. So deep scientist bit scientist idea situation. Produce old moment brother.', 'MED', '2022-03-16 17:30:11.588693', '2022-04-28 11:59:06.588693', NULL, 'ETH', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (29, 'JES', 'Over choose thus someone tend certainly. Keep here also.', 'NAMO', '2022-02-16 04:14:20.588693', '2022-07-06 03:22:32.588693', '0106000020E6100000010000000103000000010000000600000058B68D0A029303C0581E6D7459944740ABE688FD5F5503C07C7A43E610974740F3D72C1A072A03C0882CF356B3914740D7E4639FDE5603C0E0087123E58F47405AF109EBA2C903C098800E5AF490474058B68D0A029303C0581E6D7459944740', 'JIM', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (30, 'RIC', 'Between land style police. Law fine turn sign individual kitchen life. Tonight skin dog south charge.', 'MED', '2022-01-12 14:00:08.588693', '2022-01-16 00:27:04.588693', NULL, 'KAT', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (33, 'LUI', 'Check car charge say industry bed. Sign year that general.', 'NAMO', '2022-02-21 22:50:25.588693', '2022-07-12 23:31:59.588693', '0106000020E61000000100000001030000000100000004000000992B5E069D5FFABFD8A0A4D7DE27474024B03A9F54A3F9BF3040224BF32B474004F86B1CFE77F8BFE8F14452A1234740992B5E069D5FFABFD8A0A4D7DE274740', 'STE', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (36, 'MIC', 'Scientist cut scientist may interesting. Them energy teach reveal director way. History condition soldier because information first leg. Add thought one cell order.', 'MEMN', '2022-01-19 04:25:32.588693', '2022-04-20 06:14:10.588693', NULL, 'TRI', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (41, 'BRI', 'Magazine more morning we career born. Language notice site next history.', 'MEMN', '2022-07-01 00:44:16.588693', '2022-07-22 16:00:27.588693', NULL, 'MAR', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (1, 'RYA', 'Former wonder condition. Space student them investment good certainly effect.', 'MED', '2022-07-24 10:00:01', '2022-08-07 01:29:32', '0106000020E610000001000000010300000001000000C90000002EAED577FB6212C046D739EF7D2448405F559105FB6212C089E30E797D2448409230D9BFFA6212C04935A6027D2448407FDABEA6FA6212C0C9B61D8C7C2448405CA848BAFA6212C0385A93157C24484039A871FAFA6212C06D12259F7B24484013A22967FB6212C0EFCAF0287B2448401C1C5500FC6212C0CF6014B37A2448408961CDC5FC6212C0BF9AAD3D7A244840938C60B7FD6212C0DE21DAC879244840E292D1D4FE6212C0F579B75479244840F954D81D006312C02AFA62E178244840B4B02192016312C085C5F96E78244840ED954F31036312C0B0C398FD772448407C1EF9FA046312C086995C8D77244840CCA8AAEE066312C0D8A1611E77244840B7F4E50B096312C05EE6C3B076244840E84322520B6312C0A3189F4476244840177CCCC00D6312C0DE8A0EDA752448402F4C4757106312C01F292D71752448404354EB14136312C0AD72150A75244840BE4F07F9156312C00673E1A4742448402742E002196312C080BBAA41742448406AA6B1311C6312C0CE5C8AE0732448405DA0AD841F6312C08DE09881732448401731FDFA226312C04C43EE2473244840DA6CC093266312C043EEA1CA72244840F0B30E4E2A6312C063B1CA72722448405CEDF6282E6312C0D9BD7E1D72244840A5C37F23326312C03BA0D3CA7124484005E4A73C366312C0113BDE7A712448405B3F66733A6312C0A5C1B22D71244840054DAAC63E6312C006B364E370244840D94F5C35436312C0BCD4069C70244840D79C5DBE476312C0862EAB577024484073E388604C6312C05E05631670244840CD77B21A516312C054D73ED86F2448404E9EA8EB556312C075574E9D6F2448400ED933D25A6312C0A669A0656F2448404B3617CD5F6312C0DC1E43316F244840A2A010DB646312C0CDB143006F2448405F30D9FA696312C07083AED26E2448402F7E252B6F6312C0B8178FA86E24484096F6A56A746312C00413F0816E244840F42E07B8796312C00937DB5E6E244840343BF2117F6312C0BB60593F6E24484056040D77846312C0D48572236E244840F69FFAE5896312C0C9B22D0B6E24484064A85B5D8F6312C0370991F66D2448407B95CEDB946312C037BEA1E56D244840C715F05F9A6312C0041964D86D2448406B685BE89F6312C0F871DBCE6D24484047B7AA73A56312C09F310AC96D24484031717700AB6312C03CD0F1C66D244840C3A45A8DB06312C05FD592C86D244840C95AED18B66312C097D7ECCD6D2448401EF1C8A1BB6312C0E07CFED66D24484051758726C16312C0957AC5E36D244840CDFEC3A5C66312C06D963EF46D24484031091B1ECC6312C0FCA665086E2448403DCE2A8ED16312C0F39435206E244840F19E93F4D66312C03C5CA83B6E244840773CF84FDC6312C09F0DB75A6E2448408330FE9EE16312C078D0597D6E244840AF244EE0E66312C0CCE487A36E24484035399412EC6312C045A537CD6E244840015B8034F16312C0D3895EFA6E2448404198C644F66312C0462AF12A6F2448408E741F42FB6312C04141E35E6F244840893B482B006412C019AF27966F2448404A5203FF046412C0767DB0D06F244840BA8718BC096412C0ABE26E0E702448408C6355610E6412C07545534F702448404C738DED126412C0E1404D9370244840AA969A5F176412C0A8A84BDA7024484092495DB61B6412C02A8D3C2471244840D4ECBCF01F6412C069400D7171244840210DA80D246412C0405AAAC071244840FFA7140C286412C0C8BDFF1272244840216F00EB2B6412C0049EF86772244840730971A92F6412C06D837FBF72244840A5527446336412C020517E1973244840169820C1366412C0BC4ADE7573244840FED394183A6412C0E51988D47324484050E6F84B3D6412C033D46335742448402BCB7D5A406412C057015998742448406ACF5D43436412C02BA14EFD7424484048C2DC05466412C021322B6475244840422548A1486412C0AEB7D4CC75244840CE58F7144B6412C0A0C030377624484066C74B604D6412C0326E24A376244840420DB1824F6412C08D7A941077244840ED1D9D7B516412C0C03F657F772448405167904A536412C0BCBE7AEF77244840AEF115EF546412C06DA6B860782448406D7DC368566412C0CF5A02D378244840BD9D39B7576412C042FC3A4679244840E4D023DA586412C0B76E45BA79244840739538D1596412C02461042F7A244840FF7C399C5A6412C0F7545AA47A244840CD3BF33A5B6412C05CA5291A7B244840CAB53DAD5B6412C0D18E54907B244840B408FCF25B6412C0DB36BD067C24484092931C0C5C6412C019B3457D7C244840CFFA98F85B6412C06C11D0F37C2448403E2A76B85B6412C0FD5E3E6A7D2448408D53C44B5B6412C028B072E07D24484060EA9EB25A6412C0F9274F567E244840519D2CED596412C092FFB5CB7E2448402A4C9FFB586412C0D68D89407F2448405FFB33DE576412C0DF4EACB47F24484087C43295566412C06AEB00288024484060C4EE20556412C046406A9A802448408205C681536412C0C965CB0B81244840F26821B8516412C0DFB6077C812448404D8B74C44F6412C08ED802EB81244840E0A73DA74D6412C0F2C0A05882244840B37805614B6412C065BEC5C482244840D4135FF2486412C06A7E562F832448407AC6E75B466412C0C51438988324484001ED469E436412C0F90150FF83244840D4C82DBA406412C05C3A846484244840905357B03D6412C0522CBBC784244840B10F88813A6412C0FFC6DB288524484044D78D2E376412C06180CD87852448407BA73FB8336412C0DE5B78E4852448408B6A7D1F306412C0E8EFC43E8624484047BF2F652C6412C0476C9C968624484011BE478A286412C0889FE8EB862448401CBCBE8F246412C0FAFC933E87244840510C9676206412C0B1A1898E8724484078BED63F1C6412C01E5AB5DB87244840215C91EC176412C014A7032688244840BEA3DD7D136412C0AAC2616D882448402542DAF40E6412C005A5BDB188244840EA89AC520A6412C0D60806F3882448406E298098056412C0C66F2A318924484002DF86C7006412C0AD261B6C89244840E52BF8E0FB6312C06D49C9A3892448403D0511E6F66312C0CBC626D889244840418413D8F16312C0D86326098A244840D19446B8EC6312C082BFBB368A244840A7A2F587E76312C08F55DB608A244840F3457048E26312C0A0817A878A24484037EE09FBDC6312C0AB818FAA8A244840D08C19A1D76312C0A07811CA8A244840043EF93BD26312C0C770F8E58A244840D9F105CDCC6312C0625D3DFE8A244840C0139F55C76312C0C81CDA128B244840D13126D7C16312C0CF79C9238B2448406DA3FE52BC6312C0322D07318B244840902F8DCAB66312C078DE8F3A8B244840A4B2373FB16312C0152561408B244840EEC364B2AB6312C0AB8879428B244840375B7B25A66312C0D481D8408B244840E575E299A06312C0D6797E3B8B2448405CBC00119B6312C0D2CA6C328B24484063273C8C956312C06DBFA5258B24484089A5F90C906312C00B922C158B24484037C19C948A6312C00B6C05018B244840B2468724856312C0036535E98A244840B4EA18BE7F6312C0F980C2CD8A2448409AF1AE627A6312C05FAFB3AE8A24484033D7A313756312C0D8C8108C8A24484012F74ED26F6312C0A68DE2658A244840E33504A06A6312C02DA3323C8A2448408DAB137E656312C0B4910B0F8A244840494EC96D606312C089C178DE89244840AB9E6C705B6312C04F7886AA89244840FE544087566312C0CCD5417389244840970F82B3516312C0A0D0B83889244840CD026AF64C6312C0BD32FAFA88244840EDA92A51486312C0829515BA88244840BD79F0C4436312C01B5E1B7688244840D994E1523F6312C033B91C2F882448400B811DFC3A6312C075962BE587244840EBDEBCC1366312C044A45A9887244840CC22D1A4326312C0E04ABD4887244840B94F64A62E6312C0A0A767F6862448404EB478C72A6312C09F876EA1862448405DA90809276312C0A862E74986244840AD52066C236312C0E755E8EF85244840F3615BF11F6312C0F31D88938524484084DBE8991C6312C07D11DE3485244840D8DD8666196312C0191B02D4842448409C6A0458166312C04DB30C71842448408B32276F136312C084DA160C842448408163ABAC106312C078123AA583244840FB7843110E6312C01658903C83244840D90E989D0B6312C0821C34D282244840DCB64752096312C0F23E406682244840BED0E62F076312C04A05D0F8812448406164FF36056312C0B415FF898124484056FF1068036312C0696FE919812448404C9490C3016312C0A863ABA880244840BF5DE849006312C09E8E6136802448400EC377FBFE6212C0FBCF28C37F244840724093D8FD6212C0F5431E4F7F244840825184E1FC6212C0A73B5FDA7E244840DA5E8916FC6212C0CC3509657E2448402EAED577FB6212C046D739EF7D244840', 'VIC', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (9, 'CLI', 'Majority describe successful. Ahead standard language.', 'MEMN', '2022-03-10 08:20:51', '2022-06-30 10:54:47', '0106000020E6100000010000000103000000010000000C000000790D558C4ED911C0541F48DE393148404E9D47C5FFD511C0C498F4F7523048408B04AE861FD711C0F4D1F3B8B92F484004D149A58EDC11C0DFB76B53862F4840034A9E46B5DB11C073DBBE47FD2F48406286C61341DC11C0BCB1A030283048402C94F1947AE311C07CBF2C488E304840E2D92FE939E311C084921337B830484052F01472A5DE11C04969368FC33048408930348DDCD911C02F4FE78A5231484044D0E2D6EED811C06BF4C53945314840790D558C4ED911C0541F48DE39314840', 'TER', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (11, 'BRI', 'Example area order two watch travel little. Understand near they star.', 'MED', '2022-04-23 01:41:36', '2022-06-01 03:04:48', '0106000020E61000000100000001030000000100000009000000C520B072685114C08FC2F5285C2F4840B4C876BE9F1A14C00000000000384840F2D24D62109813C0F4FDD478E9364840EC51B81E856B13C03333333333334840EE7C3F355E3A13C0105839B4C82E4840A69BC420B03213C00C022B871629484048E17A14AE8713C0BA490C022B2748409CC420B072A813C02B8716D9CE274840C520B072685114C08FC2F5285C2F4840', 'KEV', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (8, 'NIC', 'Respond later simply discuss yet sport. Participant that together himself mother. Support happen girl clearly.', NULL, '2022-03-01 14:21:37', NULL, '0106000020E6100000010000000103000000010000000F000000EBBCD75AA9C911C09A65AABB0D3148406EE987C734C911C0BB54B6590631484014AEEC2708CB11C0089DC6ACCD3048407BE3FFE961CB11C052D1FD41C9304840363A8CEEC5CC11C096067E54C330484036B286E695CE11C0CA332F87DD30484024B149230BCD11C0DB9CEF4C0D314840E486DF4DB7CC11C02B1ECD470831484043531B41CFCB11C0FFC64384243148405C8FC2F528CC11C0BB078D052A3148403C5D273FF3CB11C005E91846303148403231A715F0CC11C021CB82893F314840D1820651ADCC11C07CE3B55C473148409B45DE2868C911C07E7B8D1315314840EBBCD75AA9C911C09A65AABB0D314840', 'YVO', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (6, 'MAU', 'Role morning option however bag rise check. Not among fill two blue crime. Across his score second knowledge yes.', NULL, '2022-06-13 16:10:59', NULL, '0106000020E61000000100000001030000000100000009000000BBF448E6051E12C03D29720C712E48407BB33829ED1D12C09F2D31E0762E4840866B9CEA1C1D12C0CAF2E0B4812E48409763471DFC1C12C0714A0E12812E48406C672D3F4F1B12C041857E01982E484057D0308C261912C046521C516B2E484098E4DB16C01B12C02FDA25A2462E48408E601DA6011C12C0D5FA6C2E482E4840BBF448E6051E12C03D29720C712E4840', 'KEL', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (7, 'MIC', 'Cultural staff letter give. Agency that poor third positive red capital particularly. May whether clear any someone picture bit.', 'NAMO', '2022-08-07 00:25:12', NULL, '0106000020E610000001000000010300000001000000050000005B8E5F91C27512C0B72D4634EC2A4840DDC5871BE87412C0A7348BE5D02A4840A74BB5053A6D12C00CC050D1222B4840AD7BD8C9E86D12C0B34C54A9382B48405B8E5F91C27512C0B72D4634EC2A4840', 'ROB', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (2, 'LUK', 'Attack him company article their everybody.', 'SA', '2022-05-22 10:04:10', '2022-08-06 06:23:21', '0106000020E61000000100000001030000000100000005000000FEEA55BCF63312C0BD25582F0A274840E62E16E75B3312C0AA6C84AA2127484019F3D214263212C08075CE591327484031A51A8BBF3212C0B47A13E9FB264840FEEA55BCF63312C0BD25582F0A274840', 'JES', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (3, 'HEA', 'Heavy reach forget positive business theory level. Plan loss or administration PM shoulder such.', 'NAMO', '2022-07-06 15:20:35', '2022-08-10 07:11:32', '0106000020E610000001000000010300000001000000050000008F4568E7F23112C0B64707961C274840102400352C3312C02DC0D2382A27484058877C452F3312C0961FACF1512748405D7025C4F63112C09AC9FA63442748408F4568E7F23112C0B64707961C274840', 'WIL', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (4, 'JAN', 'It loss often we stock light.', 'SA', '2022-01-04 10:54:00', '2022-04-20 09:01:52', '0106000020E61000000100000001030000000100000007000000C83922FC691F12C0858E1AB73F2E4840345DFE148E1E12C047759E08632E48403CDA29BF131E12C0CCF0FB66672E4840C4E38C74521C12C0F74063E7432E4840F6EBF44B501C12C0395A33E53E2E484093AC724D1A1E12C01D5DC3F4252E4840C83922FC691F12C0858E1AB73F2E4840', 'SCO', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (5, 'MAR', 'Reduce strategy indicate care population billion third.', 'NAMO', '2022-08-07 23:01:09', '2022-08-10 04:29:28', '0106000020E6100000010000000103000000010000000600000056AB6382071313C00C022B87163148404EC5D987CF1013C00C022B87163148408FE4F21FD20F13C069F188F7093148408FE4F21FD20F13C070BFA248E430484056AB6382071313C070BFA248E430484056AB6382071313C00C022B8716314840', 'JOR', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (44, 'JAI', 'Believe single player sister risk. Fly himself word actually. Particular matter during feel.', 'NAMO', '2022-01-14 19:20:36.588693', '2022-03-20 09:02:35.588693', NULL, 'STE', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (24, 'KAR', 'Machine office recently answer dark such toward west. Around tree green management opportunity central then. Can time into magazine.', 'MEMN', '2022-06-27 06:09:45.588693', '2022-07-03 01:03:07.588693', NULL, 'JAM', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (23, 'KIM', 'Become knowledge can effect foreign article citizen. Upon well war coach.', 'NAMO', '2022-04-29 01:55:27.588693', NULL, NULL, 'KEV', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (26, 'KAT', 'Me low southern Congress. Describe dog teach land else. Bed grow practice adult several information.', 'SA', '2022-01-02 17:47:34.588693', '2022-04-29 00:21:03.588693', NULL, 'PAT', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (21, 'HUN', 'Attack kind marriage.', 'MED', '2022-03-04 00:51:26.588693', NULL, NULL, 'MR.', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (32, 'COR', 'Rest whom analysis activity party. Camera right find soon.', 'NAMO', '2022-02-24 16:10:01.588693', '2022-03-01 22:08:38.588693', NULL, 'CHA', false, NULL, 'MONITORENV', true, NULL, '{AIR}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (42, 'KYL', 'Bring speech them spring. Whether life green loss career become save. On force debate study option push. Research appear who lawyer likely degree.', 'NAMO', '2022-04-28 02:15:59.588693', NULL, NULL, 'MR.', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (31, 'WES', 'Vote to perhaps room improve process. Four near prepare election worry Democrat step. Quality fear fire international.', 'NAMO', '2022-02-08 22:47:02.588693', NULL, NULL, 'LAU', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (37, 'DAV', 'Light drive hour ground foot fly eat all. Anything talk condition movement task company nearly seven. Analysis necessary far system. Rule within natural pay seek employee fund.', 'NAMO', '2022-02-24 13:22:25.588693', NULL, NULL, 'DWA', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (45, 'BRI', 'Maybe own each college away likely major. Former space technology million cell. Outside body my drop require.', 'MEMN', '2022-06-04 16:25:52.588693', '2022-06-07 14:21:42.588693', NULL, 'SAM', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (48, 'CHA', 'Fly chance record lawyer those. Once position indicate war medical through. Interest read possible.', 'SA', '2022-06-25 11:29:31.588693', NULL, NULL, 'MAT', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (46, 'JOS', 'And without trip key. New head director return art explain edge. Wait civil community mission attorney partner. Month cold try message.', 'SA', '2022-03-17 23:16:22.588693', NULL, NULL, 'ANN', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (43, 'DAR', 'Anything box film quality. Lot series agent out rule end young pressure.', 'MED', '2022-07-19 10:41:11.588693', '2022-07-26 21:21:57.015651', '0106000020E610000001000000010300000001000000060000004AF3CFCF7C9510C0348D456F648348404F7336C598DB0EC0481B7432AC424840CB21CD9B29570CC0DC97C7300F7648406C117FC670E60EC03C0D98345E934840F63ACBC2ED5F10C030BA1A4F249748404AF3CFCF7C9510C0348D456F64834840', 'HEI', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (34, 'STS', 'Surface different shoulder interview. Job together area probably. Of alone class capital determine machine always.', 'MEMN', '2022-07-15 21:03:12.588693', '2022-07-16 22:03:12.588693', '0106000020E61000000100000001030000000100000009000000AD0812BCE168E4BFCCDEEA3227BD4840BE63AEABD812E4BF1C5E8873F8AC484044BD156CA117DABF84C0E2AF49AC48408E16A14DE463CCBFBC9F7168A2A5484008BF4C12D0F97B3F9494F5EA3CAB4840399BF9438A28B43FDC4BF050D9BB48404BAA02B73C2CCCBF24A79C8362CD4840BC46F7A9D24DE1BFA0238D36B2D04840AD0812BCE168E4BFCCDEEA3227BD4840', 'JAM', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (47, 'CHR', 'Decision about effect sport hour field. Care finally minute stop.', 'SA', '2022-05-11 02:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'AMA', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (49, 'MIC', 'Check environment role actually whether majority blood. And action section bag middle. Somebody main stage sense.', NULL, '2022-07-28 21:54:28.588693', '2022-08-02 22:46:19.588693', '0106000020E610000001000000010300000001000000070000006A4B99E0A2F609C0F0BCE41CA7D44740A141A028CD9C09C0E0C13397F4D04740679BDF9ADA9809C0A8D2BC3DA7CF4740A669A645F8AF09C0E8FD4743E9CD47402853A486852D0AC0E059C31BBED34740D495265101290AC0CCE7F9B8F6D447406A4B99E0A2F609C0F0BCE41CA7D44740', 'MIC', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (38, 'RAN', 'Black bit sell. House relate policy once. White member worker east even anyone detail professor.', NULL, '2022-07-29 10:53:31.588693', '2022-07-31 14:24:31.858651', '0106000020E61000000300000001030000000100000005000000E1AC900B314306C0DCABC1C17F1C484077EC6F225D5006C0E9C04905DB0A4840C4FDB241475F05C0D322916C64104840C4FDB241475F05C061C3D32BE51E4840E1AC900B314306C0DCABC1C17F1C4840010300000001000000050000001A381C6D873C05C0857E01182A1748407A5824FD283005C06AB86D846A13484012C925C8E7D104C048BD6DC7D014484056F6FAE640DF04C04921B9CACD1748401A381C6D873C05C0857E01182A17484001030000000100000005000000BA44FD4709AE06C0BD44AB4926174840374C3CB9097B06C0416F22E1981148409F7BAC6C615606C0DA75EB0C3E164840F5F0C8CCC36906C01B578E56561A4840BA44FD4709AE06C0BD44AB4926174840', 'TIM', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (25, 'KEV', 'Toward agency blue now hand. Meet answer someone stand.', 'MED', '2022-06-04 20:01:28.588693', '2022-06-30 05:17:45.588693', NULL, 'CYN', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (27, 'BON', 'Out born Republican owner real case. Almost south seven service education push. Too step pay her.', 'NAMO', '2022-01-14 09:37:59.588693', '2022-05-25 09:51:46.588693', NULL, 'SCO', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (35, 'SAM', 'Beyond such seven let break enter. Perform lose seem soldier study imagine. Always space concern stop. Value today you look ahead before.', 'MED', '2022-02-23 05:35:44.588693', '2022-05-11 01:04:42.588693', NULL, 'JOH', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (39, 'KEI', 'Without black box common. More reduce many trial.', 'MED', '2022-03-02 05:42:47.588693', '2022-05-03 09:16:22.588693', NULL, 'ELI', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (40, 'TAM', 'Idea tonight interesting value.', 'NAMO', '2022-03-17 13:29:55.588693', '2022-05-27 02:14:48.588693', NULL, 'RAN', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); +INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (53, 'CDA', 'Idea tonight interesting value.', 'NAMO', '2022-11-21 13:29:55.588693', '2022-11-23 02:14:48.588693', NULL, 'CDA', false, NULL, 'MONITORENV', false, NULL, '{LAND, SEA}'); + + +SELECT pg_catalog.setval('public.missions_id_seq', 53, true); + +INSERT INTO missions_control_units + (mission_id, control_unit_id) +VALUES + ( 0, 10002), + ( 1, 10080), + ( 2, 10002), + ( 3, 10004), + ( 4, 10003), + ( 5, 10003), + ( 6, 10002), + ( 7, 10002), + ( 8, 10018), + ( 9, 10018), + ( 10, 10002), + ( 11, 10022), + ( 12, 10018), + ( 12, 10017), + ( 13, 10018), + ( 14, 10002), + ( 15, 10003), + ( 16, 10019), + ( 17, 10003), + ( 18, 10003), + ( 19, 10018), + ( 20, 10002), + ( 21, 10018), + ( 22, 10121), + ( 23, 10121), + ( 24, 10000), + ( 26, 10080), + ( 27, 10003), + ( 28, 10019), + ( 29, 10018), + ( 30, 10000), + ( 30, 10002), + ( 31, 10003), + ( 32, 10003), + ( 33, 10002), + ( 35, 10003), + ( 36, 10002), + ( 37, 10003), + ( 38, 10002), + ( 39, 10003), + ( 40, 10003), + ( 41, 10002), + ( 42, 10003), + ( 44, 10003), + ( 45, 10014), + ( 46, 10018), + ( 48, 10080), + ( 49, 10002), + ( 50, 10002), + ( 51, 10002), + ( 51, 10002); + +INSERT INTO missions_control_units + (mission_id, control_unit_id, contact) +VALUES + ( 34, 10015, '01234567890'), + ( 34, 10016, 'M. Capitaine Flame'), + ( 34, 10017, 'Popeye 06789012345'), + ( 47, 10002, 'A Team - Gimme your number'), + ( 25, 10002, 'Full contact'), + ( 43, 10018, 'Full contact'), + ( 53, 10018, 'Full contact'); + +INSERT INTO missions_control_resources + (mission_id, control_resource_id) +VALUES + ( 10, 3), + ( 10, 4), + ( 10, 5), + ( 12, 10), + ( 13, 8), + ( 14, 3), + ( 15, 6), + ( 17, 7), + ( 6, 3), + ( 7, 3), + ( 2, 3), + ( 24, 1), + ( 23, 8), + ( 26, 12), + ( 21, 10), + ( 42, 6), + ( 30, 13), + ( 31, 6), + ( 37, 6), + ( 48, 12), + ( 46, 12), + ( 43, 8), + ( 34, 11), + ( 25, 3), + ( 39, 7), + ( 40, 7), + ( 53, 8); + +UPDATE public.missions SET + start_datetime_utc = start_datetime_utc + (now() - '2022-06-01 23:00:00'), + end_datetime_utc = end_datetime_utc + (now() - '2022-06-01 23:00:00') +WHERE id > 20; diff --git a/backend/src/main/resources/db/testdata/V666.10__insert_dummy_env_actions.sql b/backend/src/main/resources/db/testdata/V666.10__insert_dummy_env_actions.sql new file mode 100644 index 0000000000..1b5c27eb5f --- /dev/null +++ b/backend/src/main/resources/db/testdata/V666.10__insert_dummy_env_actions.sql @@ -0,0 +1,57 @@ +-- +-- Data for Name: env_actions; Type: TABLE DATA; Schema: public; Owner: postgres +-- +DELETE FROM public.env_actions; + +INSERT INTO public.env_actions (id, mission_id, action_type, value, action_start_datetime_utc, geom, facade, department, action_end_datetime_utc, is_administrative_control, is_compliance_with_water_regulations_control, is_safety_equipment_and_standards_compliance_control, is_seafarers_control) VALUES +('e2257638-ddef-4611-960c-7675a3254c38', 38, 'SURVEILLANCE', '{"themes": [{"theme": "Police des activités de cultures marines", "subThemes": ["Contrôle du schéma des structures"], "protectedSpecies": []}], "observations": "", "coverMissionZone": true}', '2022-07-30 08:53:31.588693', NULL, NULL, '56', '2022-07-30 10:53:31.588693', NULL, NULL, NULL,NULL), +('f3e90d3a-6ba4-4bb3-805e-d391508aa46d', 38, 'CONTROL' , '{"themes": [{"theme": "Police des épaves", "subThemes": ["Épave/navire abandonné", "Contrôle administratif"], "protectedSpecies": []}], "infractions": [{"id": "6670e718-3ecd-46c1-8149-8b963c6f72dd", "natinf": ["10041"], "toProcess": false, "vesselSize": null, "vesselType": null, "companyName": "MASOCIETE", "formalNotice": "YES", "observations": "RAS", "relevantCourt": "LOCAL_COURT", "infractionType": "WITH_REPORT", "registrationNumber": null, "controlledPersonIdentity": null}], "vehicleType": null, "observations": null, "actionTargetType": "COMPANY", "actionNumberOfControls": 1}', '2022-07-29 11:53:31.588693', '0104000020E6100000010000000101000000399291D4BE1805C09E1A585CD6154840', NULL, NULL, NULL, NULL, NULL, NULL, NULL), +('475d2887-5344-46cd-903b-8cb5e42f9a9c', 49, 'SURVEILLANCE', '{"themes": [{"theme": "Police du conservatoire du littoral", "subThemes": ["Réglementation du conservatoire du littoral"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": false, "protectedSpecies": []}', NULL, '0106000020E61000000100000001030000000100000005000000D56979C3E95203C0BC117648B972474084387273B24D02C00C726AA38C6E4740BFFBD6B9762002C0349A2D10497347407A8D399212A102C0546E1659817A4740D56979C3E95203C0BC117648B9724740', NULL, NULL, NULL, NULL, NULL, NULL, NULL), +('16eeb9e8-f30c-430e-b36b-32b4673f81ce', 49, 'NOTE' , '{"observations": "Note libre"}', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +('6d4b7d0a-79ce-47cf-ac26-2024d2b27f28', 49, 'CONTROL' , '{"themes": [{"theme": "AMP sans réglementation particulière", "subThemes": ["Contrôle dans une AMP sans réglementation particulière"], "protectedSpecies": []}], "infractions": [{"id": "e56648c1-6ca3-4d5e-a5d2-114aa7c17126", "natinf": ["10231", "10228"], "toProcess": true, "vesselSize": null, "vesselType": null, "companyName": null, "formalNotice": "PENDING", "observations": "RAS", "relevantCourt": "PRE", "infractionType": "WAITING", "registrationNumber": null, "controlledPersonIdentity": "M DURAND"}], "vehicleType": null, "actionTargetType": "INDIVIDUAL", "actionNumberOfControls": 1}', NULL, '0104000020E61000000100000001010000003B0DADC6D4BB01C0A8387A2964714740', NULL, NULL, NULL, NULL, NULL, NULL, NULL), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 34, 'SURVEILLANCE', '{"themes": [{"theme": "Police des espèces protégées et de leurs habitats (faune et flore)", "subThemes": ["Destruction, capture, arrachage", "Atteinte aux habitats d''espèces protégées"], "protectedSpecies": ["FLORA", "BIRDS"]}, {"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": true, "protectedSpecies": []}', '2022-07-16 10:03:12.588693', NULL, NULL, NULL, '2022-07-16 12:03:12.588693', NULL, NULL, NULL, NULL), +('b8007c8a-5135-4bc3-816f-c69c7b75d807', 34, 'CONTROL' , '{"themes": [{"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "observations": "RAS", "infractions": [{"id": "5d5b7829-68cd-4436-8c0b-1cc8db7788a0", "natinf": ["10038","10231"], "toProcess": false, "vesselSize": "FROM_24_TO_46m", "vesselType": "COMMERCIAL", "companyName": null, "formalNotice": "PENDING", "observations": "Pas d''observations", "relevantCourt": "LOCAL_COURT", "infractionType": "WITH_REPORT", "registrationNumber": "BALTIK", "controlledPersonIdentity": "John Doe"}], "vehicleType": "VESSEL", "actionTargetType": "VEHICLE", "actionNumberOfControls": 1}', '2022-07-16 09:03:12.588693', '0104000020E610000001000000010100000047A07E6651E3DEBF044620AB65C54840', NULL, NULL, '2022-07-16 12:03:12.588693', NULL, NULL, NULL, NULL), +('4d9a3139-6c60-49a5-b443-0e6238a6a120', 41, 'CONTROL' , '{"themes": [{"theme": "Police des mouillages", "subThemes": ["Contrôle administratif"], "protectedSpecies": []}], "infractions": [], "vehicleType": null, "observations": "", "actionTargetType": null, "actionNumberOfControls": null}','2022-07-01 02:44:16.588693', NULL, NULL, NULL, NULL, TRUE, TRUE, TRUE, TRUE) +; + + +INSERT INTO public.env_actions VALUES +('2cdcd429-19ab-45ed-a892-7c695bd256e2', 53, 'SURVEILLANCE', '{"themes": [{"theme": "Pêche de loisir", "subThemes": ["Pêche embarquée"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": true, "protectedSpecies": []}', '2022-11-21 14:29:55.588693', NULL, NULL, NULL, '2022-11-22 12:14:48.588693'), +('3480657f-7845-4eb4-aa06-07b174b1da45', 53, 'CONTROL', '{"themes": [{"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "observations": "RAS", "infractions": [], "vehicleType": "VESSEL", "actionTargetType": "VEHICLE", "actionNumberOfControls": 0}', '2022-11-22 10:14:48.588693', '0104000020E610000001000000010100000047A07E6651E3DEBF044620AB65C54840', NULL, NULL, NULL), +('9969413b-b394-4db4-985f-b00743ffb833', 53, 'SURVEILLANCE', '{"themes": [{"theme": "Police des espèces protégées et de leurs habitats (faune et flore)", "subThemes": ["Destruction, capture, arrachage", "Atteinte aux habitats d''espèces protégées"], "protectedSpecies": ["FLORA", "BIRDS"]}, {"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": true, "protectedSpecies": []}', '2022-11-21 15:29:55.588693', NULL, NULL, NULL, '2022-11-22 13:14:48.588693') +; + +UPDATE public.env_actions SET + action_start_datetime_utc = action_start_datetime_utc + (now() - '2022-06-01 23:00:00'), + action_end_datetime_utc = action_end_datetime_utc + (now() - '2022-06-01 23:00:00') + WHERE mission_id > 20; + ; + +INSERT INTO public.env_actions_control_plan_themes (env_action_id, theme_id) VALUES +('b8007c8a-5135-4bc3-816f-c69c7b75d807', 100), +('475d2887-5344-46cd-903b-8cb5e42f9a9c', 16), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 103), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 100), +('f3e90d3a-6ba4-4bb3-805e-d391508aa46d', 15), +('e2257638-ddef-4611-960c-7675a3254c38', 9), +('4d9a3139-6c60-49a5-b443-0e6238a6a120', 12), +('6d4b7d0a-79ce-47cf-ac26-2024d2b27f28', 1) +; + +INSERT INTO public.env_actions_control_plan_sub_themes(env_action_id, subtheme_id) VALUES +('e2257638-ddef-4611-960c-7675a3254c38', 51), +('f3e90d3a-6ba4-4bb3-805e-d391508aa46d', 83), +('f3e90d3a-6ba4-4bb3-805e-d391508aa46d', 43), +('475d2887-5344-46cd-903b-8cb5e42f9a9c', 79), +('6d4b7d0a-79ce-47cf-ac26-2024d2b27f28', 48), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 100), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 102), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 117), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 118), +('b8007c8a-5135-4bc3-816f-c69c7b75d807', 102), +('4d9a3139-6c60-49a5-b443-0e6238a6a120', 42) +; + +INSERT INTO public.env_actions_control_plan_tags(env_action_id, tag_id) VALUES +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 11), +('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 15); diff --git a/backend/src/main/resources/db/testdata/V666.11__insert_dummy_reportings.sql b/backend/src/main/resources/db/testdata/V666.11__insert_dummy_reportings.sql deleted file mode 100644 index fe91ef9366..0000000000 --- a/backend/src/main/resources/db/testdata/V666.11__insert_dummy_reportings.sql +++ /dev/null @@ -1,362 +0,0 @@ -DELETE FROM reportings; - -INSERT INTO reportings ( - id, - reporting_id, - source_type , - semaphore_id , - control_unit_id , - source_name , - target_type , - vehicle_type, - target_details, - geom, - sea_front, - description, - report_type, - theme, - sub_themes, - action_taken, - is_control_required, - has_no_unit_available, - created_at, - validity_time, - is_deleted, - is_archived, - mission_id, - attached_to_mission_at_utc, - detached_from_mission_at_utc - ) -VALUES -( - 1, - 2300001, - 'SEMAPHORE', - 21, - null, - null, - 'VEHICLE', - 'VESSEL', - '[{"vesselName": "Vessel 1", "mmsi": "012314231343" }]', - ST_GeomFromText('MULTIPOINT((-4.938881879556736 48.4149566883917))', 4326), - 'NAMO', - 'Description 1', - 'INFRACTION_SUSPICION', - 'Rejets illicites', - '{"Jet de déchet","Carénage sauvage"}', - 'ACTION TAKEN', - true, - true, - now() - INTERVAL '3 days', - 24, - false, - false, - null, - null, - null - ), -( - 2, - 2300002, - 'SEMAPHORE', - 23, - null, - null, - 'VEHICLE', - 'VESSEL', - '[{"vesselName": "Vessel 2", "mmsi": "012314231344" }]', - ST_GeomFromText('MULTIPOINT((-4.779484119719514 48.619074487031526))', 4326), - 'NAMO', - 'Description 2', - 'INFRACTION_SUSPICION', - 'Police des mouillages', - '{"ZMEL"}', - 'ACTION TAKEN', - true, - true, - now() - INTERVAL '2 days', - 2, - false, - false, - null, - null, - null -), -( - 3, - 2300003, - 'CONTROL_UNIT', - null, - 10000, - null, - 'VEHICLE', - 'VESSEL', - '[{"vesselName": "Vessel 3", "mmsi": "012314231345" }]', - ST_GeomFromText('MULTIPOLYGON(((-3.504632038765229 48.938606793539606,-3.24829506967698 48.956239351532986,-3.484446288370139 48.996964545159244,-3.504632038765229 48.938606793539606)))', 4326), - 'NAMO', - 'Description 3', - 'INFRACTION_SUSPICION', - 'Police des mouillages', - '{"ZMEL"}', - 'ACTION TAKEN', - true, - true, - now() - INTERVAL '1 hour', - 1, - false, - false, - null, - null, - null -), -( - 4, - 2300004, - 'OTHER', - null, - null, - 'MA SUPER SOCIETE', - 'INDIVIDUAL', - NULL, - '[{"operatorName": "Mr le dirigeant" }]', - ST_GeomFromText('MULTIPOLYGON(((-2.81383107 49.49805557, -2.63290938 49.59886363, -2.80213877 49.69953506, -2.91683355 49.52263623, -2.81383107 49.49805557)))', 4326), - 'MED', - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultrices risus ac arcu pellentesque, et tempor justo tempor. Pellentesque sem nisl, tempor id augue non, interdum sollicitudin felis.', - 'OBSERVATION', - 'Pêche à pied', - '{"Braconnage"}', - NULL, - true, - true, - now() - INTERVAL '3 hour', - 4, - false, - false, - null, - null, - null -), -( - 5, - 2300005, - 'SEMAPHORE', - 36, - NULL, - NULL, - 'COMPANY', - NULL, - '[{"operatorName": "Ma société", "vesselName": "Mr le gérant" }]', - ST_GeomFromText('MULTIPOINT((0.37083333 49.76777778))', 4326), - 'Guadeloupe', - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - NULL, - NULL, - NULL, - true, - true, - now() - INTERVAL '1 hour', - 6, - false, - false, - null, - null, - null -); - - --- Signalements rattachés à des missions -INSERT INTO reportings ( - id, - reporting_id, - source_type, - semaphore_id, - control_unit_id, - source_name, - target_type, - vehicle_type, - target_details, - geom, - sea_front, - description, - report_type, - theme, - sub_themes, - action_taken, - is_control_required, - has_no_unit_available, - created_at, - validity_time, - is_deleted, - mission_id, - attached_to_mission_at_utc, - detached_from_mission_at_utc, - attached_env_action_id, - open_by) -VALUES - (6, - 2300006, - 'SEMAPHORE', - 36, - NULL, - NULL, - 'COMPANY', - NULL, - '[{"operatorName": "La sociéter", "vesselName": "Héron" }]', - ST_GeomFromText('MULTIPOINT((-1.59695455 43.6569585))', 4326), - 'Guadeloupe', - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - 'Police des mouillages', - '{"ZMEL"}', - NULL, - true, - true, - now() - INTERVAL '75 minutes', - 6, - false, - 34, - now() - INTERVAL '15 minutes', - null, - 'b8007c8a-5135-4bc3-816f-c69c7b75d807', - 'ABC' - ), - (7, - 2300007, - 'CONTROL_UNIT', - null, - 10001, - NULL, - 'COMPANY', - NULL, - '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', - ST_GeomFromText('MULTIPOINT((-4.18759766312331 47.11281269827924))', 4326), - 'NAMO', - 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - NULL, - NULL, - NULL, - true, - true, - now() - INTERVAL '90 minutes', - 6, - false, - 34, - now() - INTERVAL '25 minutes', - null, - null, - 'DEF' - ), - (8, - 2300008, - 'CONTROL_UNIT', - null, - 10001, - NULL, - 'COMPANY', - NULL, - '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', - ST_GeomFromText('MULTIPOINT((-1.35943753 46.02911873))', 4326), - 'NAMO', - 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - NULL, - NULL, - NULL, - true, - true, - now() - INTERVAL '90 minutes', - 6, - false, - 38, - now() - INTERVAL '25 minutes', - null, - null, - 'GHI' - ), - (9, - 2300009, - 'CONTROL_UNIT', - null, - 10001, - NULL, - 'COMPANY', - NULL, - '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', - ST_GeomFromText('MULTIPOINT((-4.40757547 48.65546589))', 4326), - 'NAMO', - 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - NULL, - NULL, - NULL, - true, - true, - now() - INTERVAL '90 minutes', - 6, - false, - 53, - now() - INTERVAL '25 minutes', - NULL, - '9969413b-b394-4db4-985f-b00743ffb833', /* a surveillance */ - 'GHI' - ), - (10, - 2300010, - 'OTHER', - null, - null, - 'Vigipol', - 'COMPANY', - NULL, - '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', - ST_GeomFromText('MULTIPOINT((-3.91241571 48.67428686))', 4326), - 'NAMO', - 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - NULL, - NULL, - NULL, - true, - true, - now() - INTERVAL '90 minutes', - 6, - false, - 53, - now() - INTERVAL '25 minutes', - NULL, - '3480657f-7845-4eb4-aa06-07b174b1da45', /* a control */ - 'GHI' - ), - (11, - 2300011, - 'SEMAPHORE', - 36, - NULL, - NULL, - 'COMPANY', - NULL, - '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', - ST_GeomFromText('MULTIPOINT((-4.76689484 48.52102012))', 4326), - 'NAMO', - 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'OBSERVATION', - NULL, - NULL, - NULL, - true, - true, - now() - INTERVAL '90 minutes', - 6, - false, - 53, - now() - INTERVAL '25 minutes', - NULL, - '9969413b-b394-4db4-985f-b00743ffb833', /* a surveillance */ - 'GHI' - ); - -SELECT setval('reportings_id_seq', (SELECT max(id) FROM reportings), true); -CREATE SEQUENCE IF NOT EXISTS reportings_2023_seq; -SELECT setval('reportings_2023_seq', (SELECT max(id) FROM reportings), true); diff --git a/backend/src/main/resources/db/testdata/V666.9__insert_dummy_semaphores.sql b/backend/src/main/resources/db/testdata/V666.11__insert_dummy_semaphores.sql similarity index 100% rename from backend/src/main/resources/db/testdata/V666.9__insert_dummy_semaphores.sql rename to backend/src/main/resources/db/testdata/V666.11__insert_dummy_semaphores.sql diff --git a/backend/src/main/resources/db/testdata/V666.12__insert_dummy_reportings.sql b/backend/src/main/resources/db/testdata/V666.12__insert_dummy_reportings.sql new file mode 100644 index 0000000000..26a577b7b8 --- /dev/null +++ b/backend/src/main/resources/db/testdata/V666.12__insert_dummy_reportings.sql @@ -0,0 +1,32 @@ +DELETE FROM reportings; + +INSERT INTO public.reportings VALUES (1, 2300001, 'SEMAPHORE', 21, NULL, NULL, 'VEHICLE', 'VESSEL', '[{"mmsi": "012314231343", "vesselName": "Vessel 1"}]', '0104000020E610000001000000010100000045035E406AC113C00CF3FE4C1D354840', 'NAMO', 'Description 1', 'INFRACTION_SUSPICION', 'Rejets illicites', '{"Jet de déchet","Carénage sauvage"}', 'ACTION TAKEN', true, true, now() - INTERVAL '3 days', 24, false, false, NULL, NULL, NULL, NULL, NULL, 19); +INSERT INTO public.reportings VALUES (2, 2300002, 'SEMAPHORE', 23, NULL, NULL, 'VEHICLE', 'VESSEL', '[{"mmsi": "012314231344", "vesselName": "Vessel 2"}]', '0104000020E610000001000000010100000062C9C715311E13C050CB31D53D4F4840', 'NAMO', 'Description 2', 'INFRACTION_SUSPICION', 'Police des mouillages', '{ZMEL}', 'ACTION TAKEN', true, true, now() - INTERVAL '2 days', 2, false, false, NULL, NULL, NULL, NULL, NULL, 12); +INSERT INTO public.reportings VALUES (3, 2300003, 'CONTROL_UNIT', NULL, 10000, NULL, 'VEHICLE', 'VESSEL', '[{"mmsi": "012314231345", "vesselName": "Vessel 3"}]', '0106000020E610000001000000010300000001000000040000006E15B8857C090CC02C07754424784840552A202082FC09C0C0FD120D667A484025BF296025E00BC0805DC2889C7F48406E15B8857C090CC02C07754424784840', 'NAMO', 'Description 3', 'INFRACTION_SUSPICION', 'Police des mouillages', '{ZMEL}', 'ACTION TAKEN', true, true, now() - INTERVAL '1 hour', 1, false, false, NULL, NULL, NULL, NULL, NULL, 12); +INSERT INTO public.reportings VALUES (4, 2300004, 'OTHER', NULL, NULL, 'MA SUPER SOCIETE', 'INDIVIDUAL', NULL, '[{"operatorName": "Mr le dirigeant"}]', '0106000020E6100000010000000103000000010000000500000012F330DDB98206C0CD5EF048C0BF4840FE7303CB321005C092CE3C90A7CC4840820740BBC76A06C07E8D665D8AD94840310109D4AC5507C002C775BEE5C2484012F330DDB98206C0CD5EF048C0BF4840', 'MED', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultrices risus ac arcu pellentesque, et tempor justo tempor. Pellentesque sem nisl, tempor id augue non, interdum sollicitudin felis.', 'OBSERVATION', 'Pêche à pied', '{Braconnage}', NULL, true, true, now() - INTERVAL '3 hour', 4, false, false, NULL, NULL, NULL, NULL, NULL, 18); +INSERT INTO public.reportings VALUES (5, 2300005, 'SEMAPHORE', 36, NULL, NULL, 'COMPANY', NULL, '[{"vesselName": "Mr le gérant", "operatorName": "Ma société"}]', '0104000020E6100000010000000101000000417927B8BBBBD73F06D9D38A46E24840', 'Guadeloupe', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', NULL, NULL, NULL, true, true, now() - INTERVAL '1 hour', 6, false, false, NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO public.reportings VALUES (6, 2300006, 'SEMAPHORE', 36, NULL, NULL, 'COMPANY', NULL, '[{"vesselName": "Héron", "operatorName": "La sociéter"}]', '0104000020E6100000010000000101000000A22CD736208DF9BF242A543717D44540', 'Guadeloupe', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', 'Police des mouillages', '{ZMEL}', NULL, true, true, now() - INTERVAL '75 minutes', 6, false, false, 'ABC', 34, now() - INTERVAL '15 minutes', NULL, 'b8007c8a-5135-4bc3-816f-c69c7b75d807', 12); +INSERT INTO public.reportings VALUES (7, 2300007, 'CONTROL_UNIT', NULL, 10001, NULL, 'COMPANY', NULL, '[{"vesselName": "Mr le gérant", "operatorName": "Good Company"}]', '0104000020E6100000010000000101000000BDAE0F9A19C010C068D780A5708E4740', 'NAMO', 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', NULL, NULL, NULL, true, true, now() - INTERVAL '90 minutes', 6, false, false, 'DEF', 34, now() - INTERVAL '25 minutes', NULL, NULL, NULL); +INSERT INTO public.reportings VALUES (8, 2300008, 'CONTROL_UNIT', NULL, 10001, NULL, 'COMPANY', NULL, '[{"vesselName": "Mr le gérant", "operatorName": "Good Company"}]', '0104000020E61000000100000001010000005BE1449141C0F5BF89869C29BA034740', 'NAMO', 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', NULL, NULL, NULL, true, true, now() - INTERVAL '90 minutes', 6, false, false, 'GHI', 38, now() - INTERVAL '25 minutes', NULL, NULL, NULL); + +/* reporting linked to a surveillance */ + + +INSERT INTO reportings (id, reporting_id, source_type, semaphore_id, control_unit_id, source_name, target_type, vehicle_type, target_details, geom, sea_front, description, report_type, theme, sub_themes, action_taken, is_control_required, has_no_unit_available, created_at, validity_time, is_deleted, mission_id, attached_to_mission_at_utc, detached_from_mission_at_utc, attached_env_action_id, open_by) VALUES +(9, 2300009, 'CONTROL_UNIT', null, 10001, NULL, 'COMPANY', NULL, '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', ST_GeomFromText('MULTIPOINT((-4.40757547 48.65546589))', 4326), 'NAMO', 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', NULL, NULL, NULL, true, true, now() - INTERVAL '90 minutes', 6, false, 53, now() - INTERVAL '25 minutes', NULL, '9969413b-b394-4db4-985f-b00743ffb833', 'GHI'), + /* reporting linked to a control */ +(10, 2300010, 'OTHER', null, null, 'Vigipol', 'COMPANY', NULL, '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', ST_GeomFromText('MULTIPOINT((-3.91241571 48.67428686))', 4326), 'NAMO', 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', NULL, NULL, NULL, true, true, now() - INTERVAL '90 minutes', 6, false, 53, now() - INTERVAL '25 minutes', NULL, '3480657f-7845-4eb4-aa06-07b174b1da45', 'GHI'), +/* reporting linked to a surveillance */ +(11, 2300011, 'SEMAPHORE', 36, NULL, NULL, 'COMPANY', NULL, '[{"operatorName": "Good Company", "vesselName": "Mr le gérant" }]', ST_GeomFromText('MULTIPOINT((-4.76689484 48.52102012))', 4326), 'NAMO', 'Lorem LoremLorem ipsum dolor sit amet, consectetur adipiscing elit.', 'OBSERVATION', NULL, NULL, NULL, true, true, now() - INTERVAL '90 minutes', 6, false, 53, now() - INTERVAL '25 minutes', NULL, '9969413b-b394-4db4-985f-b00743ffb833', 'GHI') +; + +SELECT setval('reportings_id_seq', (SELECT max(id) FROM reportings), true); +CREATE SEQUENCE IF NOT EXISTS reportings_2023_seq; +SELECT setval('reportings_2023_seq', (SELECT max(id) FROM reportings), true); + +INSERT INTO public.reportings_control_plan_sub_themes VALUES (1, 62); +INSERT INTO public.reportings_control_plan_sub_themes VALUES (1, 27); +INSERT INTO public.reportings_control_plan_sub_themes VALUES (2, 82); +INSERT INTO public.reportings_control_plan_sub_themes VALUES (3, 82); +INSERT INTO public.reportings_control_plan_sub_themes VALUES (4, 25); +INSERT INTO public.reportings_control_plan_sub_themes VALUES (6, 82); diff --git a/backend/src/main/resources/db/testdata/V666.5__insert_dummy_missions.sql b/backend/src/main/resources/db/testdata/V666.5__insert_dummy_missions.sql deleted file mode 100644 index 1059894398..0000000000 --- a/backend/src/main/resources/db/testdata/V666.5__insert_dummy_missions.sql +++ /dev/null @@ -1,161 +0,0 @@ -TRUNCATE public.missions CASCADE; - -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types, is_under_jdp) VALUES (50, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'Guadeloupe', '2022-05-11 03:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'CHA', false, NULL, 'MONITORFISH', false, NULL, '{SEA}', true); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (51, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'MEMN', '2022-05-11 04:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'CHA', false, NULL, 'POSEIDON_CACEM', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (52, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'MEMN', '2022-05-11 05:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'CHA', false, NULL, 'POSEIDON_CNSP', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (12, 'KIM', 'Mother including baby same. Evidence project air practice minute their. Trouble sing suggest maintain like know too.', 'NAMO', '2022-02-24 10:56:33', '2022-05-06 19:38:29', NULL, 'CHA', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (13, 'TYL', 'Receive hit themselves. Example community suggest seek to technology.', 'NAMO', '2022-02-07 04:16:43', '2022-07-10 19:55:50', NULL, 'ROB', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (19, 'SCO', 'Difficult ahead let really old around. Cover operation seven surface use show. Manage beautiful reason account prepare evening sure.', 'NAMO', '2022-06-21 13:24:04', '2022-07-18 02:49:08', NULL, 'EDW', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (20, 'CAS', 'South add memory sing population. Entire particularly deep yard avoid. According cell reason entire group accept.', 'MED', '2022-06-18 08:08:01', '2022-08-09 02:29:02', NULL, 'SAR', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (10, 'KIM', 'Remain vote several ok. Bring American play woman challenge. Throw low law positive seven.', 'NAMO', '2022-03-21 12:11:13', NULL, '0106000020E610000001000000010300000001000000D1070000A1B7FCB073F913C06DC43824DA364840C058840772F913C032E863C2D83648402CF3776B70F913C0D9186460D7364840E586D7DC6EF913C0F2CF4EFED5364840EC13A35B6DF913C07B0D249CD4364840409ADAE76BF913C0E757CE39D3364840E1197E816AF913C053A278D7D136484059C6E12769F913C0A1F9F774D036484095385DDC67F913C0EF507712CF3648401FA4449E66F913C020B5CBAFCD3648407F3CEC6C65F913C0C19F0A4DCC364840A39AAB4964F913C0638A49EACA36484015F2D63363F913C0E6815D87C93648405D76C22A62F913C06A797124C836484069C0C52F61F913C05FF76FC1C63648404C37894160F913C0C5FB585EC5364840F37364615FF913C09C862CFBC336484070DDFF8D5EF913C073110098C2364840B20CB3C85DF913C0BB22BE34C1364840CA6826105DF913C074BA66D1BF364840A78AB1655CF913C02D520F6EBE3648405AD9FCC75BF913C0E7E9B70ABD3648405A21B4375BF913C011084BA7BB3648401F2F83B55AF913C0ADACC843BA364840BA6912405AF913C0485146E0B8364840196AB9D859F913C0E4F5C37CB73648404F97207E59F913C07F9A4119B6364840498A9F3159F913C08CC5A9B5B43648401AAADEF158F913C098F01152B3364840AF8F35C058F913C0A51B7AEEB13648401AA24C9B58F913C023CDCC8AB03648404A7A7B8458F913C02FF83427AF364840507F6A7A58F913C0ADA987C3AD3648401A4A717E58F913C0BAD4EF5FAC364840BB41388F58F913C0C6FF57FCAA36484020FF16AE58F913C044B1AA98A9364840D3B561DA58F913C051DC1235A83648405B996C1359F913C05D077BD1A6364840A9428F5A59F913C06A32E36DA5364840CC1872AE59F913C0765D4B0AA4364840B4B46C105AF913C01202C9A6A2364840EA49D37F5AF913C0ADA64643A1364840F50BFAFB5AF913C0494BC4DF9F364840C59338865BF913C07369577C9E3648406C48371D5CF913C09E87EA189D364840D6C24DC25CF913C0571F93B59B3648408F36D0745DF913C010B73B529A3648401DD712345EF913C058C8F9EE98364840703D6D015FF913C0A1D9B78B9736484099D087DB5FF913C078648B28963648408729BAC360F913C0DE6874C594364840C27B58B961F913C0D2E6726293364840D3FAB6BB62F913C0C76471FF91364840A93F2DCC63F913C04B5C859C9036484055B163E964F913C05DCDAE398F3648404F1C061466F913C0FFB7EDD68D3648400D4DC04C67F913C02F1C42748C364840A1AA3A9268F913C0EEF9AB118B364840820121E569F913C03D512BAF89364840281E1F466BF913C01A22C04C88364840A567DDB36CF913C0856C6AEA863648406EAA072F6EF913C080302A888536484085E69DB76FF913C00A6EFF2584364840EA1BA04D71F913C0B19EFFC3823648409C4A0EF172F913C0E7481562813648409B72E8A174F913C0AD6C40008036484070C7825F76F913C09083969E7E3648400AE2342B78F913C00114023D7D3648407A29A7037AF913C0919798DB7B364840AF3631EA7BF913C0AF94447A7A364840BA707BDD7DF913C05D0B06197936484012A431DE7FF913C0B7EE07B877364840B8D053EC81F913C011D2095776364840ABF6E10784F913C018224CF674364840EB15DC3086F913C0ADEBA395733648400262966688F913C060A826357236484066A7BCA98AF913C0A3DEBED4703648408EB2FAFA8CF913C0918197746F3648408DEAF8588FF913C00F9E85146E364840624FB7C391F913C0ABAD9EB46C364840FC798D3C94F913C0F329F8546B3648406BD123C296F913C0CA1F67F5693648402922265599F913C0BF08019668364840336C94F59BF913C0D1E4C536673648408BAF6EA39EF913C0902DCBD765364840B91F095EA1F913C0DEEFE5786436484035890F26A4F913C0D91E411A63364840FEEB81FBA6F913C0F240C7BB61364840144860DEA9F913C02856785D6036484001D1FECDACF913C00BD869FF5E3648403B5309CBAFF913C00C4D86A15D364840C2CE7FD5B2F913C02AB5CD435C3648402077B6ECB5F913C0F58955E65A364840CB185911B9F913C06DCB1D8959364840C3B36743BCF913C07486FB2B58364840927B3682BFF913C0B6272FCF56364840AE3C71CEC2F913C016BC8D7255364840A12A6C27C6F913C09343171654364840E011D38DC9F913C04DB1F6B9523648406DF2A501CDF913C02412015E51364840D1FF3882D0F913C0A7DF4B025036484082063810D4F913C049A0C1A64E364840093AF7AAD7F913C026478D4B4D364840DD662253DBF913C021E183F04B364840FF8CB908DFF913C05761D0954A364840801365CAE2F913C0ABD4473B49364840C65F289AE6F913C0ACB4FFE047364840E1D8AB76EAF913C0E87A0D8746364840D37EEF5FEEF913C04234462D45364840131E9F56F2F913C0D7D3D4D34336484029EA0E5AF6F913C01AE0A37A4236484015E33E6AFAF913C00859B321413648404ED5DA87FEF913C0A43E03C93F364840D5C0E2B202FA13C07B0AA9703E364840BB0CFFE906FA13C0FF428F183D364840EE51872E0BFA13C02FE8B5C03B3648406F907B800FFA13C09B7332693A364840C6FB2FDF13FA13C0B36BEF1139364840F493A44A18FA13C0074A02BB37364840F758D9C21CFA13C0089555643636484048177A4821FA13C044C6FE0D35364840F9352FDA25FA13C0BCDDFDB733364840F64D50792AFA13C0E0613D6232364840415FDD252FFA13C040CCD20C31364840EBD07EDE33FA13C04DA3A8B72F364840E33B8CA438FA13C024DAE9622E364840B1D359773DFA13C0A77D6B0E2D3648405598E75642FA13C0670743BA2B364840D089354347FA13C0617770662A36484020A8433C4CFA13C098CDF3122936484048F3114251FA13C0090ACDBF27364840BC374C5556FA13C0B72CFC6C2636484090DC9A745BFA13C0A035811A25364840B17A55A160FA13C0C4245CC823364840317924DA65FA13C024FA8C7622364840FF705F206BFA13C04E2F2925213648402CC9AE7270FA13C0B44A1BD41F3648402F4EBED175FA13C0564C63831E3648407FCC393E7BFA13C0333401331D3648402FABC9B680FA13C04B02F5E21B364840B5B6193C86FA13C02E3054931A36484012EF29CE8BFA13C0DBBD1E44193648404454FA6C91FA13C0C4313FF5173648404DE68A1897FA13C0E98BB5A616364840B6D82FD09CFA13C0D745975815364840F4F79494A2FA13C0915FE40A143648400944BA65A8FA13C0855F87BD12364840F4BC9F43AEFA13C0B645807011364840B662452EB4FA13C03F05FA2310364840D668FF24BAFA13C004ABC9D70E364840CD9B7928C0FA13C094B0048C0D364840242F0838C6FA13C0EE15AB400C36484050EF5654CCFA13C012DBBCF50A36484053DC657DD2FA13C0728624AB093648402CF634B3D8FA13C02B0B0D6108364840EDA36CF4DEFA13C020764B1707364840FC4A1043E5FA13C06EBA0ACE053648406A52C89DEBFA13C0F8E41F850436484037BA9404F2FA13C0DBE8B53C03364840DA4E2178F8FA13C0884CB7F40136484054106EF8FEFA13C071960EAD00364840B665238405FB13C04233FC65FF354840EEE7981C0CFB13C04EB63F1FFE354840FC96CEC112FB13C0B41204D9FC3548406AA6187319FB13C056551E93FB3548403716773020FB13C0DFEACE4DFA35484063E6E9F926FB13C0A466D508F935484066E31CD02DFB13C0523572C4F7354840C74064B234FB13C03AEA6480F635484088FEBFA03BFB13C07D78D83CF53548401FE9DB9B42FB13C018E0CCF9F33548409F6760A249FB13C07EA72CB7F2354840F412A5B550FB13C03D480D75F1354840A91EFED457FB13C055C26E33F0354840BE8A6B005FFB13C0389C3BF2EE354840BA8A413766FB13C0754F89B1ED3548408CB7D77A6DFB13C00ADC5771EC354840BE4482CA74FB13C06AC89131EB3548404F3241267CFB13C0B20762F2E93548404080148E83FB13C0C4A69DB3E83548408F2EFC018BFB13C0301F5A75E7354840C7704C8192FB13C0F5709737E6354840D5DF5C0D9AFB13C0149C55FAE4354840CBE2D5A4A1FB13C01A1AAABDE335484020466348A9FB13C0EBF76981E2354840D50905F8B0FB13C016AFAA45E1354840E92DBBB3B8FB13C028B9810AE0354840E5E5D97AC0FB13C0949CD9CFDE35484040FE0C4EC8FB13C05959B295DD354840FB76542DD0FB13C077EF0B5CDC3548409D830418D8FB13C0EF5EE622DB3548409FF0C80EE0FB13C04F2157EAD935484000BEA111E8FB13C008BD48B2D83548404A1FE31FF0FB13C0AAABD07AD7354840F2E0383AF8FB13C0A473D943D63548408336F75F00FC13C0878E780DD5354840FC1F1E9108FC13C0C38298D7D3354840D46959CE10FC13C0595039A2D23548409447FD1619FC13C0D670706DD1354840B385B56B21FC13C03CE43D39D0354840BB57D6CB29FC13C08AAAA105CF354840ABBD5F3732FC13C0314A86D2CD35484083B751AE3AFC13C0C13C01A0CC354840BA11583143FC13C03982126ECB354840D9FFC6BF4BFC13C00AA1A43CCA354840E1819E5954FC13C0C312CD0BC9354840D097DEFE5CFC13C0F350A1DBC73548401F0E33B065FC13C07D68F6ABC6354840DF4B446C6EFC13C0EED2E17CC5354840871DBE3377FC13C04890634EC43548408F4F4C0780FC13C08AA07B20C3354840074997E588FC13C0B5032AF3C135484068D64ACF91FC13C0C7B96EC6C035484028C412C59AFC13C0513C5F9ABF354840597997C5A3FC13C03398D06EBE35484072C284D1ACFC13C08DC0ED43BD354840FCD22EE8B5FC13C0CF3BA119BC354840E643ED0ABFFC13C0FA09EBEFBA354840407C6838C8FC13C09BA4E0C6B935484083484C71D1FC13C025926C9EB835484037DCECB4DAFC13C096D28E76B7354840D303F603E4FC13C07FDF5C4FB635484057BF675EEDFC13C0503FC128B53548404C4296C3F6FC13C009F2BB02B43548402A592D3400FD13C0397162DDB2354840783781AF09FD13C0E1BCB4B8B1354840AFA93D3613FD13C0705B9D94B035484056E3B6C71CFD13C077C63171AF354840E6B0986426FD13C065845C4EAE354840E745370C30FD13C05A88482CAD3548405AA292BE39FD13C0A865B50AAC3548403DC6AA7B43FD13C0FC88E3E9AA354840087E2B444DFD13C0C778BDC9A935484045FD681757FD13C07ABB2DAAA8354840F24363F560FD13C0A4CA498BA735484011521ADE6AFD13C046A6116DA6354840A1278ED174FD13C05E4E854FA5354840A1C4BECF7EFD13C0EDC2A432A43548401329ACD888FD13C0658A5A16A33548406D2102ED92FD13C0E397D1FAA1354840C214690B9DFD13C0D771F4DFA035484087CF8C34A7FD13C04318C3C59F354840BD516D68B1FD13C0268B3DAC9E354840EDCE5EA6BBFD13C080CA63939D35484006E0B8EFC5FD13C0E04F4B7B9C35484018EC2343D0FD13C0B6A1DE639B3548409CBF4BA1DAFD13C004C01D4D9A3548401A8E8409E5FD13C0C9AA08379935484008247A7CEFFD13C006629F219835484068812CFAF9FD13C0485FF70C9735484039A69B8204FE13C00129FBF8953548408DF96F140FFE13C0C038C0E594354840C9E0ACB119FE13C0F61431D39335484088F64E5824FE13C0323763C192354840B8D3AD092FFE13C0E52541B0913548405A78C9C539FE13C09E5AE09F903548407E4B4A8B44FE13C0CE5B2B908F35484013E6875B4FFE13C004A337818E354840194882365AFE13C0B2B6EF728D354840A3D8E11A65FE13C0651069658C3548402664520970FE13C01EB0A3588B3548401AB77F027BFE13C0DD959F4C8A3548400905BE0586FE13C013484741893548407A81611291FE13C04F40B036883548405DC5C1299CFE13C0917EDA2C87354840C237874AA7FE13C0D902C6238635484099710976B2FE13C027CD721B85354840F2D9F0AABDFE13C07BDDE01384354840463DE9E9C8FE13C046BAFA0C83354840939BF232D4FE13C0A656EB0682354840DBF40C86DFFE13C00B399D0181354840A67C8CE2EAFE13C0E8E7FAFC7F3548406AFF1C49F6FE13C05A562FF97E354840B2B012B901FF13C0D10A25F67D354840F35C19330DFF13C04F05DCF37C3548402F0431B718FF13C0D24554F27B354840EDD9AD4424FF13C05CCC8DF17A3548402FDE8FDB2FFF13C07A129EF1793548406ADD827C3BFF13C09E9E6FF278354840290BDB2647FF13C0C97002F477354840E23344DB52FF13C0F98856F676354840A6BE66985EFF13C0BE6081F97535484064449A5F6AFF13C017F882FD74354840A6F8323076FF13C0E85B3002743548406ADB300A82FF13C04E7FB40773354840B1EC93ED8DFF13C049620F0E72354840F3F807DB99FF13C0498B2B1571354840406735D1A5FF13C050FA081D703548401004C8D0B1FF13C0EB28BD256F35484063CFBFD9BDFF13C01B17482F6E35484039C91CECC9FF13C0514B94396D3548401B253307D6FF13C01C3FB7446C354840F77B5A2CE2FF13C07CF2B0506B354840DF343B5AEEFF13C0E1EB6B5D6A354840D34FD590FAFF13C0DCA4FD6A69354840C16580D1060014C06B1D667968354840BBDDE41A130014C08F55A58867354840C0B7026D1F0014C0BAD3A5986635484049C085C82B0014C079117DA965354840DD2AC22C380014C0CC0E2BBB64354840F5C3639A440014C0B5CBAFCD6335484018BFBE10510014C033480BE162354840471CD38F5D0014C045843DF561354840F9A74C186A0014C0EC7F460A61354840B7957FA9760014C0283B2620603548400A19C042830014C0F9B5DC365F354840E0CA65E58F0014C05FF0694E5E354840C2DEC4909C0014C059EACD665D354840AF54DD44A90014C0E8A308805C354840A92CAF01B60014C00D1D1A9A5B354840AE663AC7C20014C055CF17B55A354840BF027F95CF0014C0A2C7D6D059354840DD007D6CDC0014C014F981ED583548408F94884BE90014C0A963190B583548404C8A4D33F60014C0451472295735484016E2CB23030114C003FEB6485635484075CF571C100114C057A7D26855354840DF1E9D1D1D0114C04010C58954354840DF03F0262A0114C04CB2A3AB53354840EA4AFC38370114C0ED1359CE523548408A271653440114C0B2AEFAF1513548403666E975510114C00C09731651354840763ACAA05E0114C08A9CD73B503548404CA4B8D36B0114C09CEF12624F3548402D70600F790114C0D27B3A894E3548402C056A52860114C09DC738B14D35484037FC2C9E930114C08B4C23DA4C354840D788FDF1A00114C00F91E4034C3548400CABDB4DAE0114C04588A72E4B354840D662C7B1BB0114C081C52B5A4A354840BDE3141DC90114C06FB5B18649354840B0C61B91D60114C0F3640EB448354840C172840CE40114C09A4D57E24735484067B4FA8FF10114C0656F8C1147354840A18B7E1BFF0114C0C45098414635484071F80FAF0C0214C0486B9072453548405E2E034A1A0214C07E388AA444354840E0F903ED270214C048C55AD7433548407F8E6697350214C0378B170B43354840B4B8D649430214C0BA10AB3F4235484006ACA803510214C0F048407541354840ED3488C55E0214C04ABAC1AB403548407BBA1D8E6C0214C0C7642FE33F3548409ED5C05E7A0214C0DACE731B3F35484055867137880214C09FEBB9543E354840B333D816960214C08741EC8E3D354840A6764CFEA30214C094D00ACA3C35484040B676ECB10214C0C49815063C3548406E8BAEE2BF0214C0179A0C433B354840435D9CDFCD0214C08FD4EF803A354840ADC497E4DB0214C02A48BFBF39354840BE2849F0E90214C0786E90FF38354840EC555C03F80214C0E9CD4D4038354840C17F251D060314C07E66F781373548402B3FFC3E140314C037388DC4363548403CFB8867220314C0A3BC240836354840F3B3CB96300314C0327AA84C353548403F021CCE3E0314C0E570189234354840BB80760B4D0314C0BCA074D83335484054C832505B0314C04583D21F33354840940CA59B690314C08118326832354840F21979EE770314C0526D68B131354840F7230348860314C064EEB5FB30354840A22A43A8940314C00B2FDA4630354840F42D390FA30314C0652200932F35484064FA907DB10314C071C827E02E35484003F7F2F1BF0314C0A1A73B2E2E35484049F00A6DCE0314C08439517D2D354840ADB284EFDC0314C08A0453CD2C35484040A50878EB0314C04382561E2C3548407A944207FA0314C01F3946702B354840E4B3869C080414C0AFA237C32A3548406B9C2C39170414C0F0BE2A172A35484022B5DCDB250414C056140A6C2935484009FE9684340414C06E1CEBC12835484096430734430414C039D7CD1828354840CA852DEA510414C027CB9C70273548402EF85DA6600414C057EB82C926354840386744696F0414C0AB44552326354840FB3989317E0414C022D7137E25354840650984008D0414C0DB95E9D92435484075D534D69B0414C0B88DAB36243548403E0544B1AA0414C047386F9423354840AD310993B90414C0899534F322354840D5C12C7AC80414C07DA5FB5222354840A44E0668D70414C02468C4B3213548402B3F3E5BE60414C07EDD8E1521354840E25F8054F50414C08A055B7820354840C8B0CC53040514C0BA6613DC1F354840DE312359130514C02CF4E2401F35484024E38364220514C05034B4A61E35484022F84275310514C097AD710D1E354840503D0C8C400514C0215346751D35484037E633A84F0514C05CAB1CDE1C3548404DBF65CA5E0514C0BC3CDF471C3548401BFCF5F16D0514C05DFAB8B21B3548401969901F7D0514C0B16A941E1B354840D03989528C0514C0B78D718B1A3548403F6EE08A9B0514C0706350F919354840670696C8AA0514C0DBEB3068193548404802AA0BBA0514C088A028D818354840582EC854C90514C0E807224918354840A9F198A2D80514C06BA807BB173548402AE573F6E70514C0BFEE192E17354840ED6F014FF70514C0366E18A216354840DF2A99AD060614C060A0181716354840127DE310160614C0CBFE2F8D153548408866E078250614C0E90F4904153548402C80E7E6340614C0494D797C143548401331A159440614C0CCC395F5133548403A790DD1530614C09166C96F133548401B25D84D630614C0973514EB12354840B33401D0720614C050B76067123548408EDBDC56820614C0BBEBAEE411354840A9196BE2910614C0D9D2FE621135484007EFAB72A10614C039E665E2103548401C284B08B10614C0DA25E4621035484074F89CA2C00614C09F9E4EE40F3548400D60A141D00614C034BDE5660F354840E75E58E5DF0614C0EC1469EA0E35484002F5C18DEF0614C0E798036F0E354840E955323AFF0614C02349B5F40D354840871A01EC0E0714C011AC687B0D354840F0A9D6A11E0714C0413B33030D354840129D0A5D2E0714C0237DFF8B0C354840878E991B3E0714C047EBE2150C354840B4E386DF4D0714C01E0CC8A00B354840AC037BA75D0714C03659C42C0B3548406FEE75736D0714C08FD2D7B90A354840737023447D0714C09BFEEC470A354840B88983198D0714C0E95619D70935484050A13EF29C0714C0E9614767093548402B50ACCFAC0714C02B998CF808354840CFC920B1BC0714C0AEFCE88A083548403E0E9C96CC0714C0E412471E08354840EEE9C980DC0714C05B55BCB207354840F2C3526EEC0714C014C4484807354840C068E25FFC0714C00E5FECDE0635484059D878550C0814C0BBAC917606354840BC12164F1C0814C0AA264E0F06354840E917BA4C2C0814C0D9CC21A905354840E1E7644E3C0814C0BC25F743053548402CB66A534C0814C0E0AAE3DF04354840CB82CB5B5C0814C0455CE77C04354840ABE6DE686C0814C0EC39021B04354840677CA1787C0814C0D44334BA0335484065A9168D8C0814C06F00685A033548403F083BA49C0814C04CE9B2FB02354840E33166BFAC0814C06AFE149E02354840DB59ECDDBC0814C0C93F8E41023548402680CDFFCC0814C06AAD1EE601354840C4A40925DD0814C04D47C68B013548402D944C4EED0814C0E2936F320135484072B53E7AFD0814C0478645DA0035484082A137AA0D0914C05F2B1D83003548406EBFDFDC1D0914C0B8FC0B2D00354840ADDBE2122E0914C0E27327D8FF344840C829954B3E0914C0BF9D4484FF344840AE424E884E0914C0DDF37831FF344840708DB6C75E0914C03C76C4DFFE3448400F0ACE096F0914C0DD24278FFE3448400085404F7F0914C0BFFFA03FFE34484045FE0D988F0914C0E30632F1FD34484067A98AE39F0914C0493ADAA3FD3448406486B631B00914C0EF999957FD344840B5613D83C00914C0D825700CFD3448406BA2C7D6D00914C002DE5DC2FC34484075E1AC2DE10914C06DC26279FC3448405B524187F10914C01AD37E31FC3448401DF584E3010A14C00810B2EAFB344840BBC97742120A14C03879FCA4FB34484036D019A4220A14C0A90E5E60FB344840163CBF07330A14C05CD0D61CFB344840D2D9136E430A14C0DF377CDAFA3448406AA917D7530A14C015522399FA344840DFAACA42640A14C01B12F758FA344840B81181B0740A14C0D384CC19FA3448406EAAE620850A14C05C9DCEDBF93448408AA84F93950A14C027E2E79EF934484081D86708A60A14C033531863F9344840DE6D837FB60A14C081F05F28F9344840A068A2F8C60A14C010BABEEEF83448403E957074D70A14C06F294AB6F8344840CB5A96F1E70A14C0814BD77EF834484033526B71F80A14C063139148F834484001AF43F3080B14C087076213F8344840BDA47376190B14C0EC274ADFF734484056CC52FC290B14C0937449ACF7344840DC8C89833A0B14C07BED5F7AF7344840C8B2C30C4B0B14C0340CA349F7344840193E01985B0B14C02E57FD19F7344840CF2E42256C0B14C06ACE6EEBF634484073B8DAB37C0B14C0E771F7BDF634484005DBCA438D0B14C0A6419791F6344840742F6AD69D0B14C035B76366F63448405950B569AE0B14C00559473CF6344840A4D603FFBE0B14C017274213F6344840DDF5A995CF0B14C06A2154EBF534484004AEA72DE00B14C0FF477DC4F534484091CBA8C7F00B14C06514D39EF534484094B55562010C14C00B0D407AF5344840FD0406FF110C14C0F431C456F5344840DC20629C220C14C0ACFC7434F534484021A2C13B330C14C0177A2713F5344840DDEFCCDB430C14C0539D06F3F434484087D62F7D540C14C05F6612D4F43448402056EA1F650C14C01EE21FB6F43448402FA250C3750C14C0AD035A99F43448402C870E68860C14C07D51AB7DF43448401805240E970C14C08FCB1363F43448407B4FE5B4A70C14C071EBA849F43448405466525CB80C14C095375531F43448401C161705C90C14C0FAAF181AF43448405B9287AED90C14C0A154F303F434484011DBA358EA0C14C0189FFAEEF3344840B5BC1704FB0C14C0D11519DBF3344840599E8BAF0B0D14C0CBB84EC8F3344840EC18575C1C0D14C09501B1B6F33448407E9322092D0D14C0A1762AA6F334484087DA99B63D0D14C0EF17BB96F33448407FBA68654E0D14C00C5F7888F3344840FFCD8B135F0D14C06CD24C7BF33448406E7A06C36F0D14C00C72386FF3344840DC268172800D14C0EF3D3B64F3344840C29FA722910D14C0A1AF6A5AF33448401EE579D3A10D14C0954DB151F33448407B2A4C84B20D14C05A91244AF3344840D86F1E35C30D14C0D1879943F334484034B5F0E5D30D14C018243B3EF334484008C76E97E40D14C03066093AF3344840DCD8EC48F50D14C0FB5AD936F334484027B716FB050E14C095F5D534F3344840FAC894AC160E14C00136FF33F3344840CEDA125E270E14C01E292A34F3344840A2EC900F380E14C00CC28135F3344840EDCABAC1480E14C03C87F037F3344840C0DC3873590E14C03CF28B3BF33448401D220B246A0E14C07E893E40F3344840F13389D57A0E14C0014D0846F33448404D795B868B0E14C0C53CE94CF3344840AABE2D379C0E14C05AD2F654F3344840903754E7AC0E14C030941B5EF334484075B07A97BD0E14C0D7FB6C68F3344840E45CF546CE0E14C03016C073F3344840DB3CC4F5DE0E14C05AD63F80F3344840D31C93A4EF0E14C0543CEC8DF3344840DC630A52000F14C000559A9CF3344840E5AA81FF100F14C07D1375ACF3344840EFF1F8AC210F14C0CB777CBDF33448400AA01859320F14C0CB8E85CFF3344840AE818C04430F14C09B4BBBE2F3344840DB9654AF530F14C0AD3408F7F33448401A13C558640F14C08FC3810CF4344840598F3502750F14C02405FD22F4344840AA724EAA850F14C089ECA43AF43448408389BB51960F14C0BF797953F43448406F07D1F7A60F14C0A7B94F6DF4344840E4B83A9DB70F14C05F9F5288F4344840E19DF841C80F14C059B16CA4F4344840791DB3E4D80F14C02469B3C1F4344840119D6D87E90F14C0A0D3FBDFF434484044B72428FA0F14C0EEE370FFF4344840000530C80A1014C07D20FD1FF534484057ED37661B1014C0DC02B641F5344840370994032C1014C07C118664F5344840288C989F3C1014C05F4C6D88F53448402C76453A4D1014C082B36BADF5344840CAFAEED25D1014C0E74681D3F5344840F1B2EC6A6E1014C01D80C3FAF5344840B305E7007F1014C094E51C23F634484087BF89958F1014C04C778D4CF6344840F6132928A01014C046351577F634484076CF70B9B01014C01199C9A2F634484008F26049C11014C01D2995CFF634484035AF4DD7D11014C06AE577FDF634484074D3E263E21014C0F9CD712CF73448404E9274EEF21014C0C9E2825CF7344840C3EB0277031114C06A9DC08DF7344840D2DF8DFD131114C04C8415C0F73448407C6E1582241114C06F9781F3F734484038644505351114C0D4D60428F83448401828C685451114C07B429F5DF83448400A53EF04561114C0F2536694F83448401F4C6981661114C01B182FCCF8344840CFDFDFFB761114C015822405F93448401A0E5374871114C05118313FF934484000D7C2EA971114C0CEDA547AF9344840096E835EA81114C08CC98FB6F9344840AD9F40D0B81114C08CE4E1F3F9344840EC6BFA3FC91114C05CA56032FA344840D83959ACD91114C0DF18E171FA344840D66E6017EA1114C032328EB2FA34484080A50C7FFA1114C038FE3CF4FA344840C576B5E40A1214C00E701837FB3448402E16AF471B1214C0260E0B7BFB3448403150A5A82B1214C07FD814C0FB344840E18B40063C1214C01ACF3506FC344840B5952C614C1214C0F6F16D4DFC344840243A15BA5C1214C01441BD95FC3448403FE0A20F6D1214C073BC23DFFC3448407E5481627D1214C01364A129FD344840E196B0B28D1214C0F5373675FD344840F1DA84FF9D1214C01938E2C1FD34484024EDA949AE1214C07E64A50FFE3448407BCD1F91BE1214C0B336955EFE344840F57BE6D5CE1214C09BBB86AEFE344840A65FA616DF1214C0C56C8FFFFE344840F1DD6255EF1214C0304AAF51FF34484071911890FF1214C0DC53E6A4FF34484016131FC80F1314C0CA8934F9FF3448406796CAFC1F1314C06B72844E00354840641B1B2E301314C0DC0001A500354840866EBC5C401314C08EBB94FC00354840DDF65687501314C0F3282A5501354840574D42AF601314C0293CECAE0135484008D926D3701314C01102B009023548406566B0F3801314C0C96DA065023548406EF5DE10911314C0348C92C2023548402586B22AA11314C0E1D69B2003354840104C7F40B11314C040D4A67F03354840A913F152C11314C06F77DEDF03354840EEDC0762D11314C051CD17410435484069DB176DE11314C0754F68A30435484090DBCC74F11314C0DAFDCF0605354840ED107B78011414C080D84E6B05354840807B2278111414C068DFE4D005354840481BC373211414C003997C3706354840BDBC086C311414C0DF7E2B9F0635484067934760411414C0FC90F10707354840489F7F50511414C0CD55B971073548405DE0B03C611414C0DE4698DC07354840A856DB24711414C031648E48083548402902FF08811414C0C6AD9BB508354840681670E8901414C00DAAAA2309354840542C86C4A01414C096D2D09209354840FFAAE99BB01414C060270E030A354840DF5E466FC01414C0DD2E4D740A3548407E7BF03DD01414C09B62A3E60A35484052CD9308E01414C00C49FB590B354840E58784CEEF1414C0BE5B6ACE0B354840AD776E90FF1414C02321DB430C354840AB9C514E0F1514C0CA1263BA0C354840F05DD6061F1514C0B23002320D3548406B5454BB2E1514C04C01A3AA0D354840A5B31F6B3E1514C028FE5A240E3548409D7B38164E1514C0B7AD149F0E35484053AC9EBC5D1514C08789E51A0F354840C845525E6D1514C00A18B8970F354840FC4753FB7C1514C0CED2A11510354840EEB2A1938C1514C045408D94103548409E863D279C1514C06E607A14113548400DC326B6AB1514C0D9AC7E9511354840C49BB13FBB1514C086259A171235484039DD89C4CA1514C056D7A19A123548406D87AF44DA1514C067B5C01E13354840E8CD76BFE91514C0BABFF6A313354840217D8B35F91514C0C07C2E2A14354840A2C841A6081614C078EC67B1143548406BB09911181614C0E30EA33915354840F2003F78271614C0905DF5C215354840C0ED85D9361614C0EF5E494D16354840D6766E35461614C000139FD816354840339CF88B551614C0C479F664173548404F2AD0DD641614C0CA0C65F2173548403C889D29741614C08252D580183548406F820C70831614C0ED4A47101935484062E5C8B1921614C00BF6BAA01935484024187BEDA11614C06ACD45321A3548402EE7CE23B11614C0ECDDBCC41A35484009861854C01614C0B11A4B581B354840A28DAF7FCF1614C0270ADBEC1B3548400B653CA5DE1614C051AC6C821C354840450CBFC4ED1614C02D0100191D354840C64FE3DEFC1614C0BB0895B01D3548408F2FA9F30B1714C0FCC22B491E354840B112B9011B1714C0F02FC4E21E354840915E160B2A1714C0974F5E7D1F354840CBADBD0D391714C0F021FA18203548404C99060B481714C0FBA697B5203548409E544502571714C0B9DE3653213548404913CEF2651714C02AC9D7F1213548403B6EF8DD741714C04E667A9122354840FE9818C3831714C024B61E322335484091932EA2921714C01D3FAFD323354840F55D3A7BA11714C059F456762435484029F83B4EB01714C0B7E2EA1925354840B695871ABF1714C0C98380BE253548401403C9E0CD1714C08DD7176426354840424000A1DC1714C075649B0A27354840404D2D5BEB1714C09E1D36B227354840985DA40EFA1714C0EB0FBD5A28354840497165BB081814C0EBB4450429354840CA541C62171814C00E93BAAE29354840A53B1D02261814C0E423315A2A35484050F2139C341814C06D67A9062B35484055AC542F431814C0A85D23B42B354840B269DFBB511814C0078D89622C3548406A2AB441601814C0196FF1112D3548407AEED2C06E1814C04E8A45C22D3548405B82E7397D1814C036589B732E3548401E4D9AAB8B1814C0415FDD252F354840B1E742179A1814C0FF1821D92F35484027B9897BA81814C0E10B518D30354840F68D1AD9B61814C076B18242313548401E66F52FC51814C0BD09B6F831354840A0411A80D31814C09921C0AF323548400454DDC8E11814C027ECCB6733354840C169EA0AF01814C06869D9203435484060B69545FE1814C0CD1FD3DA3435484059068B790C1914C0560FB99535354840AB59CAA61A1914C002388B5136354840DFE3A7CC281914C061135F0E37354840F6A423EB361914C0E3271FCC37354840EF9C3D02451914C019EFE08A383548404198A112531914C0E375794A3935484075CAA31B611914C05FAF130B3A3548408C33441D6F1914C000229ACC3A354840FC9F2E187D1914C0C4CD0C8F3B354840D7760B0B8B1914C0ACB26B523C354840948486F6981914C0464ACC163D35484034C99FDAA61914C075A103DC3D354840B54457B7B41914C057AB3CA23E35484019F7AC8CC21914C0CE744C693F35484060E0A05AD01914C0F7F05D314035484011348720DE1914C044A65BFA40354840A5BE0BDFEB1914C0261B30C4413548401B802E96F91914C0BA42068F42354840FCAB4345071A14C0E329B35A43354840C00EF7EC141A14C0304A4C2744354840EEDB9C8C221A14C0301DE7F444354840FFDFE024301A14C0C4AF58C3453548407B4E17B53D1A14C07D7BB692463548406227403D4B1A14C0CA06EB62473548402C3707BE581A14C0C94421344835484061B1C036661A14C05E422E064935484000966CA7731A14C0167927D9493548400BE50A10811A14C0F2E80CAD4A354840829E9B708E1A14C06218C9814B35484063C21EC99B1A14C0F78071574C354840AF509419A91A14C0AF22062E4D3548406749FC61B61A14C0FC8371054E3548408AAC56A2C31A14C06C1EC9DD4E354840187AA3DAD01A14C07278F7B64F3548409AE5360ADE1A14C09B0B12915035484088BBBC31EB1A14C0E8D7186C51354840E0FB3451F81A14C0CA63F64752354840A4A69F68051B14C041AFAA24533548405CEF5077121B14C0DB334B025435484008D6487D1F1B14C00A78C2E0543548401F27337B2C1B14C05DF525C055354840A1E20F71391B14C0453260A056354840A06F875D461B14C0C12E7181573548400B67F141531B14C0D3EA586358354840E1C84D1E601B14C008E02C465935484033FC44F16C1B14C0D294D7295A354840F1992EBC791B14C0C0826E0E5B354840A3D55E7E861B14C0B3B6C6F35B3548404AAFD537931B14C0CB230BDA5C354840E42693E89F1B14C0775026C15D354840723C9790AC1B14C029C302A95E354840F5EFE12FB91B14C0FF6ECB915F354840F474C7C5C51B14C069DA6A7B603548405F649F53D21B14C06905E16561354840472512D8DE1B14C0FDEF2D51623548402284CB53EB1B14C0279A513D63354840F280CBC6F71B14C0E5034C2A64354840B61B1231041C14C0372D1D1865354840F887F391101C14C01F16C50666354840B6C56FE91C1C14C09CBE43F666354840DF6DDE38291C14C01EAD83E6673548400E1B3C7E351C14C0365B9AD7683548403266E0BA411C14C0E2C887C969354840494FCBEE4D1C14C023F64BBC6A354840673DA5185A1C14C0F9E2E6AF6B35484078C9C539661C14C0D41543A46C3548407EF32C52721C14C0450876996D3548408A2283607E1C14C0BC406A8F6E354840122374658A1C14C0C73835866F3548408FC1AB61961C14C067F0D67D7035484089317E54A21C14C00DEE3976713548400073EB3DAE1C14C048AB736F723548407DB9471DBA1C14C089AE6E6973354840EE9DEAF3C51C14C05F7140647435484065877CC0D11C14C03B7AD35F75354840D00E5584DD1C14C01DC9275C76354840419B1C3EE91C14C093D75259773548402FF97EEEF41C14C0102C3F5778354840235CD094001D14C021400256793548409590BC310C1D14C0AA2071557A354840839643C5171D14C0C7C0B6557B35484077A1B94E231D14C07920D3567C354840E87DCACE2E1D14C0A24C9B587D354840D62B76453A1D14C060383A5B7E354840531265B1451D14C095F0845E7F354840C5969A14511D14C05F68A66280354840C553136D5C1D14C02F2689678135484042E226BC671D14C0052A2D6D82354840C5752901731D14C0E0739273833548404E0E1B3C7E1D14C0C203B97A843548405478A76D891D14C01B608B828535484061E72295941D14C0097C348B86354840FC8EE1B19F1D14C0FCDD9E948735484014083BC5AA1D14C0670CB59E88354840328683CEB51D14C0D7808CA9893548405609BBCDC01D14C04E3B25B58A35484009C535C2CB1D14C0CA3B7FC18B35484039524BADD61D14C04D829ACE8C354840F817A48DE11D14C0469561DC8D35484034AF9764EC1D14C046EEE9EA8E354840FF7ECE30F71D14C0BC131EFA8F354840588748F2011E14C0C8F8280A913548402F615DAA0C1E14C0BB30CA1A923548409573B557171E14C0B5AE2C2C9335484089BE50FA211E14C0B472503E94354840FBDA86932C1E14C02B0320519535484085635421371E14C0A7D9B064963548408BBDBCA5411E14C09B7CED7897354840A983BC1E4C1E14C005ECD58D98354840CE4EAB8D561E14C076A17FA399354840F81E89F2601E14C05D23D5B99A354840B127AA4C6B1E14C0BC71D6D09B354840F9680E9C751E14C0210699E89C354840D0E2B5E07F1E14C0FD6607019E3548403695A01A8A1E14C04F94211A9F354840A24C7A4A941E14C0198EE733A03548409D3C976F9E1E14C05A54594EA13548402765F789A81E14C012E77669A23548403FC69A99B21E14C041464085A3354840E75F819EBC1E14C076EBCAA1A43548401D32AB98C61E14C093E3EBBEA5354840E33C1888D01E14C028A8B8DCA63548403780C86CDA1E14C0333931FBA7354840A32F1046E41E14C0B596551AA935484015E44615EE1E14C0AFC0253AAA3548409F0415D9F71E14C01FB7A15AAB354840B85D2692011F14C07800B47BAC3548405FEF7A400B1F14C04816729DAD3548401FED66E3141F14C08FF8DBBFAE3548406D23967B1E1F14C04DA7F1E2AF3548404B920809281F14C0F3A89D06B1354840406D128B311F14C081FDDF2AB2354840C4805F023B1F14C01598E34FB3354840D7CCEF6E441F14C092857D75B43548408BB86BCF4D1F14C0F6C5AD9BB535484045A9D625571F14C0D2D289C2B63548409F392D70601F14C09632FCE9B73548408802C7AF691F14C0D15E1A12B93548400104A4E4721F14C0F4DDCE3ABA3548401AA56C0D7C1F14C0FFAF1964BB354840C27E782B851F14C0824E108EBC35484082C41B3E8E1F14C0EC3F9DB8BD354840D0420246971F14C03F84C0E3BE354840C060D441A01F14C07A1B7A0FC03548403EB7E932A91F14C09D05CA3BC13548405DADEA17B21F14C037BCC568C23548400CDC2EF2BA1F14C02B4C4296C3354840D1760AC1C31F14C095A86AC4C4354840AF7D7D84CC1F14C0E85729F3C53548402E24DC3BD51F14C094E06822C73548403B037EE8DD1F14C0B7355452C8354840604EB789E61F14C03464C082C93548402639DC1EEF1F14C0275FD8B3CA354840049098A8F71F14C0743371E5CB354840FA52EC26002014C0A95AA017CD3548400882D799082014C0C6D4654ACE354840B650AE00112014C03D28AC7DCF354840F357C85C192014C09BCE88B1D03548405A3222AC212014C0E2C7FBE5D13548405045BFF0292014C0829AEF1AD3354840E6F74729322014C00AC07950D4354840951668563A2014C07B389A86D5354840E4D47377422014C0458A3BBDD63548404BFF168D4A2014C068B55DF4D735484053C9A596522014C07333162CD9354840FB3220945A2014C0D88A4F64DA354840BC083286622014C024351F9DDB354840944ADB6C6A2014C0CBB86FD6DC3548400D2C7047722014C0CA154110DE35484027ADF0157A2014C0B1C5A84ADF354840E1CD5CD8812014C063D57B85E0354840B45A608F892014C0FE37E5C0E135484027874F3A912014C0F173CFFCE23548403B532AD9982014C03E893A39E4354840668B9C6CA02014C0E4772676E5354840BC964EF3A72014C0E33F93B3E6354840290E986EAF2014C0CB5A96F1E73548403725CDDDB62014C07DD50430E93548406F0F4240BE2014C08829F46EEA354840BF654E97C52014C0ED5664AEEB354840AF5B46E2CC2014C01CE43FEEEC35484040F12921D42014C033C4B12EEE3548407226F953DB2014C014048F6FEF35484045FBB37AE22014C04F1DEDB0F0354840B86F5A95E92014C0E30FCCF2F135484055B740A3F02014C042621635F33548400A6BBEA5F72014C0FA8DE177F4354840E9F17B9BFE2014C00B932DBBF535484068182585052114C0E7F7E4FEF635484089DEB9620C2114C08DBC0743F8354840D2778E33132114C08C5AAB87F9354840347DFAF8192114C0E5D1CFCCFA354840C055A6B1202114C0792F4A12FC3548407501925D272114C0F5DF5A58FD354840421915FE2D2114C0AD76C19EFE3548403804D891342114C0BFE6A8E5FF35484059C2DA183B2114C09AB6FB2C013648401A20C993412114C040E6B974023648407C1DA302482114C0B175E3BC0336484008EEBC644E2114C0EC64780505364840345EC2BA542114C0802D8E4E063648408AA107045B2114C04FDCF9970736484081843841612114C07864E6E108364840A13AA971672114C0DDD2282C0A364840639005966D2114C09B1AEC760B364840D7ECF5AC732114C0944805C20C36484062B57DB8792114C058D6890D0E364840A18499B67F2114C0E6C379590F36484080F3A0A8852114C0B097BFA5103648408935E88D8B2114C0D34486F21136484033171B67912114C032D8A23F133648408FFFE132972114C0CC51158D143648408C8794F29C2114C0BFA408DB153648402AAF32A6A22114C0EEDD5129173648407ADD644CA82114C059FDF07718364840F4DED6E5AD2114C08E7CFBC6193648400F803473B32114C0FEE15B161B36484054F4D1F3B82114C039A727661C364840C23BAF67BE2114C0AF5249B61D3648405A56CCCEC32114C061E4C0061F3648401C442929C92114C0DED5A357203648400705C676CE2114C095ADDCA8213648401D99A2B7D32114C0896B6BFA223648405B00BFEBD82114C04789654C24364840C43A1B13DE2114C0B113A09E253648405648B72DE32114C0E6FD45F1263648401229933BE82114C0C8542C4428364840F8DCAE3CED2114C0740B7E972936484090975E30F22114C0CC2E10EB2A364840C9F1F917F72114C0EFB10D3F2C364840B55229F2FB2114C0BFA14B932D364840415344C0002214C059F1F4E72E364840805AF380052214C0A0ADDE3C30364840E934E2340A2214C093D60892313648407BE210DC0E2214C0515F9EE732364840C096D375132214C0BC54743D34364840A6EA8103182214C06230A093353648403F45C4831C2214C043F221EA36364840017346F7202214C0D120E4403836484076A75C5D252214C00CBCE6973936484014AFB2B6292214C011B754EF3A364840DD8948032E2214C035A5ED463C364840CE371E43322214C09379DC9E3D36484073EC8775362214C09EBA0BF73E3648404174319B3A2214C0E5E1904F40364840C2026FB33E2214C0D87556A8413648406D64ECBE422214C079765C01433648404199A9BD462214C0545DB85A44364840C8D4FAAE4A2214C04D373FB4453648400117E0924E2214C082F71B0E47364840DCF8B06A522214C06424396848364840F2146A34562214C0F2BD96C249364840A8D00EF2592214C09E4A1F1D4B3648409BC69BA15D2214C086BDFD774C3648402D5C1445612214C01A9D1CD34D364840FC2B75DA642214C0CC6F662E4F364840F4CE1563682214C0B928068A503648401645F6DE6B2214C0C4D4D0E551364840EBC16A4D6F2214C07CEDDB4153364840724573AE722214C0E172279E54364840239CBB02762214C063EB9DFA5536484086F99749792214C092D0545757364840142AB4837C2214C06D224CB458364840546164B07F2214C067676E115A364840469FA8CF822214C00D19D16E5B36484062B02CE2852214C0D1BD5ECC5C36484031C844E7882214C0B255172A5E364840B2E6F0DE8B2214C0405A10885F3648405ED8DCC98E2214C07BCB49E660364840BBD05CA7912214C045B6984462364840CCCF7077942214C0BB0D28A3633648408FD5183A972214C04F58E201653648407CAE00F0992214C00196C760663648401B8E7C989C2214C06040EDBF673648406D748C339F2214C04D64281F69364840726130C1A12214C0E7F4A37E6A364840A0211442A42214C010FF34DE6B36484081E88BB5A62214C0E675063E6D36484015B6971BA92214C0D9DF029E6E3648405B8A3774AB2214C05CC314FE6F364840CB3117C0AD2214C0FC99515E713648407613DFFDAF2214C0B963B9BE723648404CC8E62EB22214C095204C1F74364840D3838252B42214C08ED00980753648400E46B268B62214C017FADCE076364840FB0E7671B82214C0BD16DB41783648409BDECD6CBA2214C0F1ACEEA2793648406481655BBC2214C044362D047B364840E02A913CBE2214C0B4B296657C364840980EA50FC02214C0B4A815C77D36484079C5F8D5C12214C04218AA287F3648400D83E08EC32214C0EE7A698A8036484054475C3AC52214C029573EEC813648404D126CD8C62214C081263E4E83364840F9E30F69C82214C0696F53B084364840CE88F3ECC92214C0DF317E1286364840DF67BF62CB2214C0E46DBE7487364840A34D1FCBCC2214C0792314D7883648409106BF26CE2214C02ACC94398A364840BAF94674CF2214C0DC74159C8B3648400CC00EB5D02214C0AC10C1FE8C3648409BC0BEE7D12214C07CAC6C618E3648405394AE0DD32214C0693B43C48F364840BD6E3226D42214C056CA19279136484063839E30D52214C0D3D2058A92364840336B4A2ED62214C0DE5407ED93364840B6598A1ED72214C078501E5095364840EB4E5E01D82214C0A1C54AB3963648405B7E1AD6D82214C0CA3A771698364840F680169ED92214C08229B97999364840438AA658DA2214C03A18FBDC9A364840439ACA05DB2214C0808052409C364840F5B082A5DB2214C0C7E8A9A39D364840E3012337DC2214C09DCA16079F364840FA2503BCDC2214C00126996AA0364840C4507733DD2214C066811BCEA136484041827F9DDD2214C0CADC9D31A336484071BA1BFADD2214C02F382095A4364840DC2CA048DE2214C0220DB8F8A53648407072648ADE2214C016E24F5CA7364840B8BEBCBEDE2214C009B7E7BFA8364840B211A9E5DE2214C0FC8B7F23AA3648405E6B29FFDE2214C07FDA2C87AB36484046FF910ADF2214C072AFC4EAAC36484058663A09DF2214C0F4FD714EAE3648401DD476FADE2214C0E8D209B2AF3648401D7C9BDDDE2214C06A21B715B136484047F7FFB3DE2214C05DF64E79B23648402379F87CDE2214C051CBE6DCB33648403B35D937DE2214C044A07E40B53648407DC4F9E5DD2214C0377516A4B6364840715AAE86DD2214C09CD09807B8364840A12A4B19DD2214C0002C1B6BB9364840FACD279FDC2214C065879DCEBA36484006789817DC2214C03B690A32BC3648404E5CF181DB2214C0104B7795BD364840C0138ADFDA2214C057B3CEF8BE364840E4D1B62FDA2214C09E1B265CC036484043CACB71D92214C0E4837DBFC1364840CD9520A7D82214C00DF9A922C3364840096809CFD72214C0366ED685C43648408074DAE8D62214C05FE302E9C53648402154EBF5D52214C06A65044CC7364840753A90F5D42214C076E705AFC83648407C27C9E7D32214C0F2EFF111CA364840BE4EEACBD22214C0DF7EC874CB3648402A494BA3D12214C03E9489D7CC364840484A406DD02214C09CA94A3ACE3648401952C929CF2214C0DDCBE09CCF3648409D60E6D8CD2214C08F7461FFD0364840D375977ACC2214C0B2A3CC61D2364840BC91DC0ECB2214C0D5D237C4D336484057B4B595C92214C04C956226D5364840A6DD220FC82214C0C2578D88D6364840A60D247BC62214C0A9A0A2EAD7364840D11065DAC42214C073F68C4CD9364840374E8E2BC32214C0AED261AEDA364840C75EF76FC12214C0CBBB0B10DC36484092A948A6BF2214C0E8A4B571DD36484087C7D9CFBD2214C058211FD3DE3648402FECFEEBBB2214C03A247334E03648408917B8FAB92214C08DADB195E1364840964905FCB72214C0C143C5F6E23648405682E6EFB52214C06760C357E4364840C8C15BD6B32214C0611081B8E536484064D410B0B12214C05AC03E19E73648403B21AE7BAF2214C0A703BC79E83648403C418B3AAD2214C065CD23DAE9364840F067FCEBAA2214C0762A4B3AEB36484056950190A82214C0F80D5D9AEC364840E7954627A62214C05DFE43FAED364840B2D073B0A32214C03275155AEF364840A8DEE02CA12214C05B7FA6B9F036484050F3E19B9E2214C066960C19F2364840AA0E77FD9B2214C054BA4778F33648402FFD4B52992214C023EB57D7F4364840EE250999962214C046AF2736F6364840D82106D3932214C0DBF9E194F7364840EBF04200912214C0C2D75BF3F83648403AFA671F8E2214C08CC2AA51FA364840B3D6CC318B2214C038BACEAFFB364840DEB9C536882214C0C6BEC70DFD364840BCA3522E852214C0A856806BFE364840C3601F19822214C0DC81F8C8FF3648407E2480F67E2214C0F4B945260137484061BB20C77B2214C0EDFE678302374840818CA989782214C03AD749E00337484041FD1D40752214C0DA42EB3C053748403DA87AE8712214C05CBB619906374840622617846E2214C032C797F5073748403AAB47126B2214C05A668D51093748403C03B893672214C0661258AD0A374840F161BC07642214C0C451E2080C374840CF93006F602214C076242C640D3748405FCCD8C85C2214C07B8A35BF0E3748401AD8F015592214C0D483FE191037484087EA9C55552214C08010877411374840A703DD87512214C07F30CFCE12374840F0EF5CAD4D2214C0D2E3D6281437484063AF1CC6492214C0782A9E8215374840897570D1452214C0710425DC16374840D80E04D0412214C02FF8553518374840DAAE2BC13D2214C0CFF85B8E19374840062293A5392214C034130CE71A3748405C683A7D352214C0ECC07B3F1C37484064B57547312214C0688895971D37484096D5F0042D2214C0C65C84EF1E3748407AFCFFB4282214C05BD107472037484088F64E58242214C0D152609E21374840C0C3DDEE1F2214C07D744DF522374840AB9700781B2214C00BA30F4C24374840360B0FF5162214C0CF7166A2253748407485B164122214C0E6D37CF8263748406406E8C60D2214C051C9524E28374840F5260A1D092214C0F15EBDA329374840394EC065042214C0E487E7F82A374840A748B6A1FF2114C09CCABB4D2C3748403E16ECD0FA2114C0A7A04FA22D374840FFB661F3F52114C0E81678F62E374840735E6B08F12114C07C20604A3037484087A56011EC2114C0D543F29D313748404EF3E90CE72114C0630719F1323748403F14B3FBE12114C0455EFF4334374840D0D467DEDC2114C05C557A9635374840159CB0B3D72114C0C6DFB4E8363748408236397CD22114C0660A843A383748401AA40138CD2114C0CB4EFD8B39374840DBE409E7C72114C0F4AC20DD3A374840C6F85189C22114C0E124EE2D3C37484052AC851FBD2114C0043D507E3D37484090664DA8B72114C0EC6E5CCE3E374840F8F35424B22114C098BA121E4037484001214894AC2114C079A65D6D4137484034217BF7A62114C01FAC52BC4237484090F4ED4DA12114C0FB51DC0A44374840169BA0979B2114C09B11105945374840C51493D4952114C07171D8A6463748409F61C504902114C00BEB4AF447374840194EE3288A2114C0DB04524149374840BC0D4140842114C0E0BEED8D4A3748408AA0DE4A7E2114C01B191EDA4B374840F8D26749782114C01A8DF8254D37484090D8303B722114C04FA167714E37484052B139206C2114C0B9556BBC4F3748403D5D82F8652114C05AAA030751374840C9A8B6C45F2114C02F9F305152374840F693D684592114C0C9AD079B533748404C523638532114C00AE35DE454374840CDE3D5DE4C2114C081B8482D56374840EE146179462114C02D2EC8755737484039192C07402114C00E44DCBD5837484024BDE288392114C025FA84055A374840B00085FE322114C07250C24C5B374840661767672C2114C065CD7E935C374840BDCD34C4252114C08EEACFD95D3748403D5742141F2114C0EDA7B51F5F3748405F803B58182114C0810530656037484021492090112114C0BC8929AA613748400CE544BB0A2114C09E34A2EE62374840992055DA032114C0B57FAF3264374840C6FB50EDFC2014C0026B517665374840947638F4F52014C0F57C72B96637484003910BEFEE2014C01E2F28FC673748409B7E1EDDE72014C0EE075D3E693748404CD8C8BFE02014C0640711806A3748402605B395D92014C010A759C16B374840A0D1885FD22014C0D4F30B026D374840BC3D4A1DCB2014C05C5A68426E3748407849F7CEC32014C0FD6D2E826F374840D5F48F74BC2014C043A873C170374840D33F140EB52014C0C0824D0072374840E9F62F9CAD2014C0540A913E7337484028818B1DA62014C01E32697C7437484008ABD2929E2014C08E80C0B9753748400041B1FC962014C0167C81F67637484099767B5A8F2014C0D417D73278374840D24B31AC872014C0AA60966E79374840ADC0D2F17F2014C0B549EAA97A37484028D55F2B782014C0D8DFA7E47B374840BB558459702014C0A29CE41E7D374840EE75947B682014C084068B587E3748403A023C92602014C09B10C6917F374840AF61239C582014C0CAC76ACA80374840B3F94D9B502014C0112C790282374840E164B88D482014C08D301C3A833748409E086675402014C09368137184374840847F5350382014C0CD409FA7853748408262D81F302014C020C694DD8637484098B1F4E3272014C08BF8F31288374840C66CA89C1F2014C09C51D2478937484095C74749172014C0C5571A7C8A37484004C2D2E90E2014C0060BCCAF8B37484003F5A07F062014C0EDE4FCE28C374840A2C75A09FE1F14C0ED6B97158E3748405906AC87F51F14C004A09B478F374840B0E4E8F9EC1F14C0338109799037484097FB6861E41F14C00989F6A9913748401EB2D4BCDB1F14C0F63D4DDA92374840BED4D70CD31F14C0FC9F0D0A9437484075637251CA1F14C08A35223995374840BB2A508BC11F14C0BFF1B56796374840A19119B9B81F14C00C5BB39597374840A0647ADBAF1F14C070711AC398374840B6A372F2A61F14C0ED34EBEF99374840E54E02FE9D1F14C0F22B101C9B3748402B6629FE941F14C09E49B4479C37484000B693F38B1F14C0D39AAC729D37484076A5E9DC821F14C020990E9D9E3748407ACD82BB791F14C0F6CAC4C69F3748409761B38E701F14C07223FAEFA0374840422E2757671F14C077AF8318A2374840056732145E1F14C095E87640A3374840E10BD5C5541F14C03B55BE67A4374840D31C0F6C4B1F14C0F96E6F8EA537484055668C07421F14C040BC74B4A637484066E84C98381F14C09EB6E3D9A7374840180AF91C2F1F14C0155EBCFEA8374840CF309497251F14C085BFD322AA3748409EC3C6061C1F14C09C476A46AB37484085C2906A121F14C0AE893F69AC37484073C649C4081F14C0D7787E8BAD37484078369A12FF1E14C0899B11ADAE37484094128255F51E14C0C4F1F8CDAF374840B7F3588EEB1E14C017F549EEB0374840F240C7BBE11E14C0F22BEF0DB2374840BBC678DED71E14C05796E82CB337484014856DF6CD1E14C04534364BB437484084AFF902C41E14C0BB05D868B5374840FADE7405BA1E14C0BA0ACE85B6374840FF4633FDAF1E14C0434318A2B737484093E734EAA51E14C054AFB6BDB83748403FF4CDCB9B1E14C0EE4EA9D8B9374840F10556A3911E14C01122F0F2BA37484032502170871E14C0BE288B0CBC37484001D32F327D1E14C0F3627A25BD374840D75A2DEA721E14C0B1D0BD3DBE374840C54EC296681E14C069F83F55BF374840B84746395E1E14C0A953166CC03748403A790DD1531E14C073E24082C1374840C3AFC35E491E14C0372BAA97C2374840DA1EBDE13E1E14C084A767ACC337484080C6F959341E14C05A5779C0C43748402C7325C8291E14C0B93ADFD3C53748406758942B1F1E14C0825E6EE6C6374840A842F284141E14C0642F67F8C7374840EF313FD4091E14C040BA9E09C9374840C559CF18FF1D14C016FF141ACA374840A1864E53F41D14C07477DF29CB3748400CEC1083E91D14C0CDA9E838CC374840F3226EA9DE1D14C0AF0F4647CD3748406A920EC5D31D14C0FCB5CC54CE374840E7069ED6C81D14C06009BD61CF37484069801CDEBD1D14C0309DD66DD03748407B32DEDAB21D14C089644479D137484009B63ACEA71D14C0DCE5F083D23748409E3E86B79C1D14C02921DC8DD337484038CCC096911D14C070160697D4374840D95EEA6B861D14C0B0C56E9FD53748407FF602377B1D14C0EB2E16A7D63748402C930AF86F1D14C0AFCB11AED7374840DE3401AF641D14C0DFA836B4D83748400EA8925C591D14C097B9AFB9D9374840432013004E1D14C0BA0A52BEDA3748407F9D8299421D14C0D71533C2DB37484037EC8C29371D14C07D5468C5DC374840F63F86AF2B1D14C08FD3C6C7DD37484031651A2C201D14C00B934EC9DE374840728F9D9E141D14C010862ACADF374840318BBB07091D14C0103345CAE0374840F58BC866FD1C14C07B2089C9E1374840375E70BCF11C14C0DFC70BC8E2374840F501B308E61C14C0AFAFB7C5E3374840BAAAE44ADA1C14C07951A2C2E4374840FC24B183CE1C14C03DADCBBEE5374840BA7018B3C21C14C0FBC233BAE6374840F68D1AD9B61C14C02419C5B4E7374840AE7CB7F5AA1C14C0B9AF7FAEE83748406D7043089F1C14C0470079A7E937484020021612931C14C0CF0AB19FEA37484050658312871C14C0C3551297EB374840FD998B097B1C14C022E19C8DEC37484026A02EF76E1C14C07B266683ED374840CD776CDB621C14C03FAC5878EE37484068EDF0B6561C14C06E72746CEF374840096864884A1C14C097F2CE5FF03748409F801E513E1C14C02BB35252F137484028371F11321C14C02BB4FF43F23748402EBFBAC7251C14C0246FEB34F3374840B118F174191C14C0896A0025F437484029106E190D1C14C0CA2C2914F53748401DD985B4001C14C005A99002F63748400640E446F41B14C0AB6521F0F6374840E34489D0E71B14C0BD62DBDCF73748403C1BC950DB1B14C0C819D4C8F83748408A8F4FC8CE1B14C0B097E0B3F9374840CCA11C37C21B14C00356169EFA3748408B85849CB51B14C0C1547587FB374840B5D3DEF9A81B14C0EA93FD6FFC3748405DF3D34D9C1B14C07E13AF57FD3748406F7DBB998F1B14C07ED3893EFE374840FFD83DDC821B14C0E9D38D24FF374840F99EB216761B14C0309BA50900384840E8026E48691B14C0E2A2E6ED00384840CB0470715C1B14C08E6466D101384840A2A4B8914F1B14C08873E4B3023848406DE247A9421B14C07B3CA19503384840A38AC9B8351B14C04BCC717604384840CDD091BF281B14C0869C6B5605384840ECB4A0BD1B1B14C02CAD8E35063848407603A2B30E1B14C0AF84C51307384840F3EFE9A0011B14C09D9C25F107384840DC462486F41A14C0677B99CD0838484030085163E71A14C09C9A36A9093848407967C437DA1A14C0AD80E7830A3848402C312A04CD1A14C02AA7C15D0B3848404B6582C8BF1A14C08394AF360C3848405D372184B21A14C047C2C60E0D38484052405E38A51A14C0E7B6F1E50D3848403BE7E1E3971A14C0F3EB45BC0E3848408FF857878A1A14C0DAE7AD910F3848404F74C0227D1A14C09EAA296610384840F126C7B66F1A14C03F34B9391138484086771442621A14C04AFE710C12384840FEFEFFC5541A14C0328F3EDE12384840E1F0DD41471A14C0856034AF13384840304DAEB5391A14C0257F287F14384840E91371212C1A14C031DE454E153848408511D2851E1A14C01804771C163848408C7925E2101A14C04E77A6E91638484075181737031A14C07DA414B617384840CA21FB83F51914C0F91E8181183848408995D1C8E71914C05260014C19384840A20CF206DA1914C0876895151A38484026EE043DCC1914C099373DDE1A384840163A0A6BBE1914C016470EA61B3848405E895992B01914C0E0A3DD6C1C38484012439BB1A21914C086C7C0321D3848401F0027CA941914C008B2B7F71D3848409727A5DA861914C06763C2BB1E384840F285C1E3781914C0A2DBE07E1F3848402F1B7CE56A1914C0BA1A1341203848404EE7D4DF5C1914C01FA7430221384840C6B677D34E1914C0EF739DC221384840A9F00CBF401914C00C8EF58122384840E62DECA3321914C0066F61402338484005A26981241914C04D9DCBFD233848407D193158161914C0FF0B5FBA24384840D8C79627081914C0FFC7F0752538484015AD9AEFF91814C0DB4A963026384840AB95E8B0EB1814C0041B3AEA263848409B81806BDD1814C009B2F1A2273848406CA4B61ECF1814C05C96A75A2838484097CA36CBC01814C01BBB861129384840A5275570B21814C097B34EC7293848408254690FA41814C07FEC3F7C2A38484042B81BA7951814C025F919302B3848405C1F1838871814C037461DE32B384840CE895EC2781814C096E01E952C3848409AF7EE456A1814C042C81E462D384840BF68C9C25B1814C03CFD1CF62D3848403EDDED384D1814C0A17244A52E3848408D2108A93E1814C0C4BB54532F384840BE9CC011301814C0C4CB780030384840BFE76E74211814C011299BAC303848401A3667D0121814C03A4DD1573138484045545526041814C02245F00132384840CA758D75F51714C0757D38AB32384840A89A0FBEE61714C08689695333384840CD5B3301D81714C0745CAEFA33384840D553F53CC91714C0AF7CF1A03438484024E85873BA1714C038EA324635384840CC7F06A3AB1714C00EA572EA3538484045E7A9CC9C1714C0C026C68D36384840175297EF8D1714C0317C0230373848403059260D7F1714C07E9852D137384840A363FF23701714C01902A171383848405D0A7A35611714C001B9ED1039384840E880EA40521714C036BD38AF39384840CCFAA445431714C0B80E824C3A384840F7100145341714C089ADC9E83A384840F3F6523E251714C0A6990F843B38484036794632161714C0A04C691E3C384840D3FE831F071714C058D3ABB73C3848402EED0E08F81614C05EA7EC4F3D384840E2DEE3E9E81614C0B1C82BE73D384840DE6C5AC6D91614C05137697D3E3848402197729DCA1614C03FF3A4123F3848403591806EBB1614C07AFCDEA63F3848409027303AAC1614C00353173A40384840335A81009D1614C04A7D38CC40384840A65CC8C08D1614C06D6E6D5D41384840D7C75C7C7E1614C04F338BED41384840D902E7316F1614C07F45A77C4238484022DA12E25F1614C0FBA4C10A433848402A1A8C8D501614C0C651DA9743384840022AFB32411614C04ED2DB234438484022D60BD3311614C0B319F1AE4438484000EB696E221614C0D734EF3845384840269C6904131614C0B923D6C14538484093E90A95031614C0E85FBB4946384840BF9FF920F41514C0F462B4D04638484032F289A7E41514C02FC080564738484063AD6729D51514C046E460DB47384840DC04E7A5C51514C08E62145F4838484014C5B31DB61514C0B1A7DBE14838484093212290A61514C093C08B6349384840D1E6DDFD961514C0C2263AE449384840CD14E766871514C0B060D1634A38484087AB3DCB771514C0ECE766E24A38484089DE352A681514C074BCFA5F4B384840C1462785581514C0BB6477DC4B384840B71766DB481514C0C1E0DC574C384840F584462C391514C014AA40D24C38484068272079291514C0B5C0A24B4D3848409A3247C1191514C014ABEDC34D384840017367050A1514C03169213B4E384840B04F2944FA1414C09C7453B14E3848409461E47EEA1414C0C6536E264F384840AEA898B5DA1414C03C80879A4F38484086589AE7CA1414C07280890D503848401D71E914BB1414C0F5CD897F50384840EABE313EAB1414C0A7755DF050384840EC4173639B1414C036E4446051384840AD2D02848B1414C0F4ACFFCE513848401A1B36A17B1414C000C3B83C523848404671B7B96B1414C0CAAC5AA952384840A7FC31CE5B1414C0E1E3FA14533848403EBDA5DE4B1414C0B8EE837F533848400BB312EB3B1414C04CCDF5E8533848400DDE78F32B1414C09F7F505154384840453ED8F71B1414C0407FA9B8543848402AA0DCF80B1414C09F52EB1E553848404437DAF5FB1314C0BCF91584553848409303D1EEEB1314C0997429E8553848401805C1E3DB1314C0C23C3B4B563848404A0856D5CB1314C01B5F20AD56384840290D90C3BB1314C0C2CE030E573848403D47C3ADAB1314C02712D06D5738484087B6EF939B1314C0D9A29ACC57384840F4F36C778B1314C0BB8D382A583848409766E3567B1314C0EBC5D48658384840E7DAFE326B1314C0D8D159E258384840E350BF0B5B1314C0F637B23C5938484015FC78E04A1314C061EB0896593848406B7583B23A1314C08B7248EE593848406DF032812A1314C073CD70455A3848401C6D874C1A1314C0A875979B5A38484078EB80140A1314C00D7891F05A384840806B1FD9F91214C0314E74445B384840ACB90E9BE91214C0A27155975B3848408509A359D91214C042EF09E95B38484081278815C91214C030BABC395C3848402A4712CEB81214C04EDF42895C38484080684183A81214C0B951C7D75C384840FA57C135981214C0531E1F255D384840971592E5871214C03B3875715D38484058A1B392771214C053AC9EBC5D384840C52E7A3C671214C029F4B0065E384840578A91E3561214C04D89C14F5E3848400CB4F987461214C0A078A5975E384840E4ABB229361214C041B587DE5E384840E171BCC8251214C0114C3D245F38484078D2C265151214C0A0B6DB685F384840BC346EFF041214C0EDF462AC5F3848409B311697F41114C0F906D3EE5F3848409DFC0E2CE41114C0C3EC2B3060384840C39558BED31114C04CA66D706038484084C99E4EC31114C0933398AF6038484069CB35DCB21114C00A1B96ED60384840719B1D67A21114C0CE4F922A613848408CD2ADF0911114C0C2DE616661384840CAD78E77811114C075411AA1613848402BABC0FB701114C075F1D0DA613848409FE59A7E601114C0158245136238484036EEC5FE4F1114C00360B84A623848406891ED7C3F1114C0B01114816238484035CF11F92E1114C08C1D43B6623848401474DE731E1114C0B67670EA6238484017E7FBEB0D1114C00F2A711D63384840B4F41562FD1014C026B15A4F633848406369D8D6EC1014C06E92178063384840AD789749DC1014C003C1D2AF63384840922253BACB1014C0C74961DE633848408833B729BB1014C04AA6D80B643848401ADF1797AA1014C08BD6383864384840BDF120039A1014C08BDA816364384840FB9E266D891014C0BB389E8D643848404BB3D4D5781014C038E4B8B664384840AD2E2B3D681014C0E4E9A6DE6438484021112AA3571014C0C0496805653848402F8E2507471014C0EAF6272B653848404F72C969361014C043FEBA4F6538484082BD15CB251014C05BD93673653848403D3CB62B151014C031889B95653848409355538A041014C03791D3B665384840FAD598E7F30F14C0FC6DF4D665384840EB893244E30F14C07E1EFEF565384840EEA4749FD20F14C0C0A2F0136638484079F30AFAC10F14C03181B630663848409FDC9D52B10F14C0EFAC7A4C66384840C6C530ABA00F14C04FB9FC66663848408749C001900F14C0FB127D806638484048CD4F587F0F14C0D7C6D098663848401BB887AD6E0F14C0724E0DB066384840000A68015E0F14C0CBA932C666384840E45B48554D0F14C0545F2BDB66384840DB14D1A73C0F14C09CE80CEF66384840D2CD59FA2B0F14C0A245D70167384840DAED8A4B1B0F14C066768A13673848406C41109C0A0F14C05A01112467384840FD9495ECF90E14C00D60803367384840A04FC33BE90E14C0EF18C34167384840440AF18AD80E14C090A5EE4E6738484070F872D9C70E14C0EF05035B673848409CE6F427B70E14C00D3A006667384840DA3B1F75A60E14C05AC8D06F67384840905DF5C2950E14C0662A8A7867384840CEB21F10850E14C030602C8067384840953B9E5C740E14C02AF0A186673848405CC41CA9630E14C0E353008C67384840234D9BF5520E14C05A8B479067384840EAD51942420E14C0011D6293673848403A92EC8D310E14C06682659567384840011B6BDA200E14C08ABB51966738484051D73D26100E14C0DD4E1196673848401860BC72FF0D14C0EFB5B99467384840681C8FBEEE0D14C0BFF04A92673848402FA50D0BDE0D14C04EFFC48E67384840F62D8C57CD0D14C00D68128A67384840BDB60AA4BC0D14C0FB2A338467384840FB0B35F1AB0D14C0363B527D673848403A615F3E9B0D14C0A1A544756738484078B6898B8A0D14C0CBE31F6C673848402DD85FD9790D14C0247CCE616738484059C6E127690D14C0CB617B566738484085B46376580D14C01328E64967384840296F91C5470D14C0A73B4F3C6738484043F66A15370D14C06CA98B2D67384840D549F065260D14C0EFEAB01D67384840DD6921B7150D14C03000BF0C67384840E6895208050D14C0A26FA0FA66384840DC42DB5AF40C14C0D1B26AE7663848404AC80FAEE30C14C0BFC91DD3663848402F1AF001D30C14C0DD3AA4BD663848408B387C56C20C14C049F928A766384840D5EF5FACB10C14C054986B8F663848409673EF02A10C14C0AE84AC7666384840CEC32A5A900C14C037CBC05C66384840F4ACBDB27F0C14C07EE5BD41663848409262FC0B6F0C14C084D3A325663848401DB192665E0C14C0BA1B5D0866384840979880C24D0C14C03DB114EA65384840874C1A1F3D0C14C061278ACA6538484066990B7D2C0C14C0D2EAFDA965384840AA4B00DD1B0C14C0730845886538484065CAA03D0B0C14C0D2F97465653848400FE2989FFA0B14C0F0BE8D4165384840A692E802EA0B14C0CC578F1C653848402CDC8F67D90B14C0D84A64F6643848409FBE8ECDC80B14C0A31122CF6438484078069135B80B14C02CACC8A6643848403FE7EA9EA70B14C0731A587D64384840F4609C09970B14C0EAE2BA52643848400F405176860B14C0207F06276438484017B85DE4750B14C014EF3AFA633848400EC9C153650B14C0C73258CC63384840E10BD5C5540B14C0A9D0489D63384840A2E73F39440B14C0D9BB376D63384840C828AEAE330B14C03801FA3B63384840DC027425230B14C0561AA50963384840CD0EE99E120B14C0330739D662384840ACB3B519020B14C03F4EA0A162384840F0BD8596F10A14C098E2056C6238484010FA0416E10A14C021D13E35623848401ECFDB96D00A14C0699360FD6138484009D6611AC00A14C06F296BC4613848405942EB9FAF0A14C033935E8A613848400E1478279F0A14C02857254F613848409F17B4B18E0A14C06968EA12613848409680F33D7E0A14C0DAD382D560384840F14E36CC6D0A14C00A130497603848402A4F285D5D0A14C0F8256E57603848403E81C9F04C0A14C03486D61660384840B7186E863C0A14C010C7FCD45F38484084AE6D1F2C0A14C03A5521925F3848403FDDC4B91B0A14C023B72E4E5F3848404E0A77570B0A14C0C9EC24095F3848403869D8F7FA0914C0A07CEEC25E384840FFF9E89AEA0914C0C459B67B5E3848402BF0FC3FDA0914C0A60A67335E384840ABE46BE8C90914C0B815EBE95D384840060B8A93B90914C0186E6D9F5D3848403E635741A90914C0A720C3535D384840CAB97FF2980914C0F4A601075D384840BA75ABA5880914C08F7A3EB95C38484075FCDD5C780914C05AA84E6A5C38484095E81316680914C072235D1A5C384840809F50D3570914C0B9F83EC95B384840CFBB9092470914C04E1B1F775B384840EAA2D755370914C01398D2235B384840E0BBCD1B270914C0256284CF5A3848402AD31EE5160914C0F5FF1E7A5A384840C7E8CAB1060914C0F6F78C235A384840B7FCD181F60814C0433DF9CB59384840FB0E3455E60814C04F564E73593848401B53452BD60814C01A438C195938484006625D05C60814C0A303B3BE58384840446FD0E2B50814C0EB97C26258384840D57A9EC3A50814C08079D00558384840305173A8950814C044B5B1A7573848406859F78F850814C0563E914857384840E2F82D7C750814C0279B59E85638484037CA136B650814C0B6CB0A87563848405766005E550814C004D0A4245638484042CDF354450814C09F213DC1553848408032424F350814C069CDA85C553848408862974D250814C081C612F7543848405A5DF34F150814C05893659054384840F7225656050814C07CADB62854384840E8E61360F50714C0CF21DBBF53384840A275D86DE50714C070E3FD55533848409F9B4F80D50714C05FF21EEB52384840EEBF2196C50714C07C5B137F523848407F7BA6B0B50714C0E811061252384840643586CEA50714C0129CE1A3513848408A8618F1950714C08973BB3451384840F16E5D18860714C030A568C450384840AC55FD42760714C0B39D295350384840A8D34F72660714C066F0BDE04F384840E6E854A6560714C06690506D4F384840EEC860DE460714C0B47DE1F84E384840C073731A370714C031C545834E384840D4B5385B270714C08BD3BD0C4E384840298FB0A0170714C0143C09954D384840C0FFDAEA070714C0EAF1521C4D3848409907B839F80614C00EF59AA24C3848403CDA9B8CE80614C0F1CBCB274C384840204432E4D80614C021F0FAAB4B384840BD112741C90614C00FE8122F4B38484024AA22A2B90614C04B2D29B14A38484044A67C08AA0614C0454628324A3848402E6DDD729A0614C08DAC25B249384840D1979CE28A0614C093E60B31493848402C26BA577B0614C0E76DF0AE48384840527FDED06B0614C08842D32B48384840303C614F5C0614C0E7EA9EA747384840C75C42D34C0614C094E06822473848409F14D65B3D0614C000AA1B9C46384840B9631CE92D0614C0B8C0CC144638484002E36C7C1E0614C0BF247C8C453848408DF96F140F0614C012D629034538484059A725B1FF0514C0245BC078443848405585E553F00514C0842D55ED4338484093FA57FBE00514C0314DE8604338484000A0D4A8D10514C09C4064D342384840AEDC035BC20514C0E4FAF344423848408D493D13B30514C0EA886CB541384840AC4D29D0A30514C03E64E32441384840FB811F93940514C05013439340384840031A745B850514C03F89B60040384840C4152729760514C07A4C286D3F384840B341E4FC660514C075E382D83E384840E50454D5570514C0BCC7DB423E384840BDC479B4480514C0E07248AC3D3848404EE8FD98390514C0C3F19D143D384840976FE0822A0514C0F3BDF17B3C3848401027CD721B0514C070D743E23B384840B80EC4680C0514C03B3E94473B3848409026C564FD0414C053F2E2AB3A38484021A22466EE0414C0B9F32F0F3A384840E14D8E6DDF0414C0FABB907139384840D129027BD00414C0FB57DAD238384840F035808EC10414C048412233383848403F7208A8B20414C072F17D923738484035AB46C8A30414C05B75C2F036384840E347E3ED940414C020C01A4E36384840C1148A19860414C0325871AA3538484046DEE64B770414C0923DC60535384840FAD74D84680414C03F70196034384840DE01BFC2590414C0C86980B9333848406828E6074B0414C01037D01133384840237F17533C0414C034CB33693238484083D2FEA42D0414C03426ABBF313848408B229CFD1E0414C0F3540B1531384840C2A2435C100414C08E4A7F69303848402953F5C0010414C0768DF1BC2F384840ADCC082DF30314C03B97770F2F3848406176269FE40314C04DEEFB602E384840BC1CFA17D60314C0AD927EB12D384840BEBF8397C70314C0E9FD14012D384840665FC31DB90314C072B6A94F2C384840B5FBB8AAAA0314C0D835529D2B384840AA94643E9C0314C08B02F9E92A384840462AC6D88D0314C01A96B3352A38484089BCDD797F0314C0F7766C8029384840EA175722710314C0B01E39CA28384840F16F86D1620314C0B6130413283848409FC46B87540314C099CFE25A27384840F4150744460314C05752D5A12638484066300408380314C06422C6E725384840F71363D3290314C04CB9CA2C253848402DF477A51B0314C01117E37024384840829DEE7E0D0314C023C2F9B3233848407D431B5FFF0214C0123424F62238484096B2A946F10214C0DD6C623722384840CDEA9935E30214C0F5F29E772138484022ECEB2BD50214C0E93FEFB6203848401DEAF328C70214C0BA5353F51F384840AD7D092EB90214C0672ECB321F384840E40DD539AB0214C0F0CF566F1E3848403867024D9D0214C05638F6AA1D38484022563D688F0214C009EE93E51C384840290EDA8A810214C027E45A1F1C3848404E8FD8B4730214C0932720581B38484090D938E6650214C069AB0E901A384840F1ECFA1E580214C08E7CFBC619384840E695CA5F4A0214C01D8E11FD18384840F907FCA73C0214C0FAEC253218384840A10F3BF82E0214C0418C63661738484066E0DB4F210214C0D7789F9916384840C0468AAF130214C0D7A504CC1538484038769A16060214C0B4997DFD14384840453BB885F80114C06D540A2E1438484070C937FCEA0114C002D6AA5D13384840A6B9707BDD0114C00298748C12384840FB720B02D00114C0DF2052BA11384840E4C1B390C20114C0987043E71038484062A66927B50114C02D8748131038484075202DC6A70114C02EDE763E0F3848401C30FE6C9A0114C00AFCB8680E38484059D5DC1B8D0114C0C3E00E920D3848402A10C9D27F0114C0E8058EBA0C38484090E0C291720114C0E8F120E20B38484002137659650114C0C5A4C7080B384840910E8B28580114C00D98972E0A3848402D6C59004B0114C0C0CB905309384840D42BE1E03D0114C04FC69D7708384840118176C9300114C04A01D49A07384840E26B19BA230114C020031EBD06384840BFB875B3160114C0624591DE05384840319BDFB4090114C0804E18FF04384840AEDF02BFFC0014C00A98C81E043848403886DFD1EF0014C0FE21A23D0338484056C2C9ECE20014C0CF728F5B0238484081606D10D60014C00B04A67801384840B760CA3CC90014C0B2D5E59400384840F9C2E071BC0014C0C5E74EB0FF374840D0BA04AFAF0014C0B3C0CBCAFE3748402AE18DF5A20014C09C5387E4FD374840189D2444960014C061AD56FDFC3748408A87209C890014C091474F15FC37484090072AFC7C0014C02C22712CFB3748401AB69865700014C0333DBC42FA374840AFC6C0D7630014C0A4983058F93748405039A252570014C08134CE6CF837484075DAE8D64A0014C0C9109580F7374840A5DDE8633E0014C07C2D8593F6374840E042A2F9310014C09A8A9EA5F53748409FD6C098250014C02428E1B6F43748406ACC9840190014C018064DC7F337484041242AF10C0014C0079EF7D6F23748409AAA20AB000014C06176CBE5F1374840775F7C6EF4FF13C0258FC8F3F03748406076913AE8FF13C056E8EE00F03748404288B710DCFF13C0F1813E0DEF374840B92FEBEECFFF13C086D5CC18EE3748402BD22FD7C3FF13C087698423ED374840A8D62DC8B7FF13C081B77A2DEC3748401FD63CC3ABFF13C058CC8436EB374840A23705C79FFF13C0B814E33EEA374840A8C732D493FF13C0839D6A46E93748403286C5EA87FF13C0B9661B4DE8374840B53F690B7CFF13C0E9E90A53E7374840445BC63470FF13C084AD2358E6374840CD71346864FF13C01A2B7B5CE537484062EA5BA458FF13C01AE9FB5FE4374840F05D94EA4CFF13C01561BB62E33748400200323A41FF13C00993B964E23748400E9DE09335FF13C0F87EF665E13748409D68F4F629FF13C052AB5C66E0374840AF626D631EFF13C0A6910166DF374840BB57F7D912FF13C0F331E564DE3748404A7BE65907FF13C0AC12F262DD374840D299E6E3FBFE13C060AD3D60DC37484055B3F777F0FE13C09C7BDD5CDB3748405BFB6D15E5FE13C0438AA658DA374840E47149BCD9FE13C0E452AE53D9374840DEAFE16DCEFE13C07FD5F44DD83748405B1CDF28C3FE13C015127A47D7374840D283EDEDB7FE13C0A4083E40D637484042E60CBDACFE13C02EB94038D5374840AD433D96A1FE13C0409D972FD43748409BCFD27896FE13C0BEC11726D3374840FA2225668BFE13C035A0D61BD2374840DCA4DC5C80FE13C036B2E910D13748402FEE505E75FE13C0307E3B05D03748407C32D6696AFE13C02504CCF8CE374840C3716C7F5FFE13C0A3BDB0EBCD37484004AC139F54FE13C08BB7BEDDCC3748403FE1CBC849FE13C0FDE420CFCB374840ECDD40FD3EFE13C0F845D7BFCA3748401B091B3B34FE13C0EC60CCAFC937484032C85D8429FE13C0DB35009FC8374840CDB505D71EFE13C0523E888DC7374840D86A6A3414FE13C0C4004F7BC6374840DD1AE09B09FE13C0BFF66968C53748405492120EFFFD13C0B3A6C354C43748403BD1018BF4FD13C0318A7140C33748401D0B0212EAFD13C037A1732BC2374840700CBFA3DFFD13C03872B415C1374840BD088D3FD5FD13C0C17649FFBF3748407ACC17E6CAFD13C0D4AE32E8BE374840A9575F97C0FD13C0E0A05AD0BD374840D2DDB752B6FD13C076C6D6B7BC3748406C2BCD18ACFD13C02399BC9EBB37484078409FE9A1FD13C03BACCB84BA3748406BE9D9C597FD13C06C6C446AB9374840588D25AC8DFD13C02560114FB8374840402C829C83FD13C067873233B73748400F5F479879FD13C0A3689216B63748405059C99E6FFD13C0F7F65BF9B4374840021B08B065FD13C0D4B879DBB33748409B70AFCC5BFD13C039AEEBBCB23748402FC167F351FD13C028D7B19DB137484034D9DC2448FD13C0A033CC7DB03748402285BA613EFD13C0A0C33A5DAF37484080F854A934FD13C0B900133CAE3748404F33ACFB2AFD13C05A713F1AAD37484007026C5921FD13C08415C0F7AB3748402F98E8C117FD13C0C666AAD4AA374840C9F521350EFD13C00272D3B0A93748404BE7C3B304FD13C0E5A37B8CA8374840B56CCE3DFBFC13C0C28F6267A737484019EDE9D1F1FC13C046A2C841A6374840DCCD1972E8FC13C0C36E6D1BA53748401176061DDFFC13C059E87BF4A3374840B6E5AFD2D5FC13C0060FF4CCA2374840BBB56D94CCFC13C0CBE2D5A4A1374840314DE860C3FC13C019EA0B7CA037484018AC1F38BAFC13C0F02496529F3748405E6B6B1BB1FC13C06E869F289E37484015F27309A8FC13C0741BFDFD9C374840B50CE5029FFC13C0935DC4D29B3748403CBBBE0796FC13C0C94CF5A69A374840ACFD00188DFC13C0886F7A7A993748408D07003384FC13C0EEB87E4D98374840CD71135A7BFC13C0DC35D71F97374840F56F8F8C72FC13C072D9AEF195374840050274CA69FC13C090B0DAC294374840875B151361FC13C055AE8593933748406815CB6758FC13C0A3DF8463923748403063E9C74FFC13C09837033391374840E244703347FC13C016C3D50190374840F2860BAB3EFC13C03A7527D08E3748407390632D36FC13C0054EF89D8D37484054FACFBB2DFC13C0595A1D6B8C3748401DF8A45525FC13C0548DC1378B37484045568EFB1CFC13C0666DCF038A3748405548E0AC14FC13C090FA46CF883748404DCE9A690CFC13C061AE3D9A873748402DE8BD3104FC13C04A0F9E64863748406D62F505FCFB13C04B1D682E853748400C3D41E6F3FB13C081CBC6F78337484093ABF5D1EBFB13C040AD79C08237484003AE12C9E3FB13C0A6B5AB888137484048DDEFCCDBFB13C0B2E45C5080374840FFD389DBD3FB13C0663A8D177F3748408CF7E3F6CBFB13C0313D27DE7D37484001AFA61DC4FB13C0A26640A47C3748405EFAD14FBCFB13C0BBB6D8697B3748409272BD8EB4FB13C0EBB3DA2E7A374840AE7E11D9ACFB13C0C2D75BF37837484029EB792FA5FB13C040225CB7773748408CEB4A919DFB13C06493DB7A76374840C518DCFF95FB13C0BEA4EF3D75374840E7D9D5798EFB13C0A1E9570074374840DFC78F0087FB13C0B9CE54C272374840BF49B2927FFB13C00754E68371374840FE2BE93078FB13C06D86E144703748409D6E34DB70FB13C07ADF5B056F3748409A11949169FB13C02D5F55C56D374840F714085462FB13C0167FE3846C3748402B453C235BFB13C0A5C5F0436B3748404609D9FD53FB13C0DC327D026A374840C12D8AE44CFB13C047409EC068374840127FFBD745FB13C05A743E7E67374840C23081D73EFB13C013CF5D3B663748405A766FE237FB13C002CA11F864374840C9E81DFA30FB13C097EB44B4633748400E888C1E2AFB13C0D433F76F623748403BBB634E23FB13C0D495532B613748403F1BFB8A1CFB13C0EDA419E65F374840A1DBA6D315FB13C0CACD89A05E374840DAC812290FFB13C04D1D795A5D3748407316938A08FB13C0060DFD135C3748406AC427F801FB13C0662300CD5A374840389F7C72FBFA13C08B53AD855937484065DAE5F8F4FA13C056AAD93D5837484068420F8CEEFA13C056A19AF556374840CB0A4D2BE8FA13C08D38F0AC553748408C339FD6E1FA13C06AF6C463543748402589B18EDBFA13C00BCE431A53374840930B8453D5FA13C0E24557D05137484060EE6A24CFFA13C0EF5DFF855037484004FE1102C9FA13C031163C3B4F3748407F3A79ECC2FA13C0A86E0DF04D37484058D7F4E2BCFA13C0566773A44C37484008A130E6B6FA13C0C87983584B37484017CB80F5B0FA13C0E0B2120C4A37484073EE3C12ABFA13C0BD054CBF483748402E720D3BA5FA13C0D0F81972473748404956F26F9FFA13C0A705922446374840B13343B299FA13C0B3B29ED6443748407971A80094FA13C084795588433748408DA8795C8EFA13C08BE0A0394237484001405FC488FA13C0C7E780EA40374840D537593883FA13C0C8080B9B3F374840F528BFB97DFA13C08D433F4B3E374840EC46E54778FA13C0871E08FB3C374840B991CBE272FA13C047137BAA3B374840E63CC6896DFA13C0CA2198593A37484060E12C3E68FA13C084D049083937484039E6A7FE62FA13C00199A5B6373748405FE48ECC5DFA13C0437BAB64363748405C0F36A758FA13C04A775B1235374840B79AF18D53FA13C0158DB5BF33374840611F19824EFA13C0A5BCB96C32374840E0D0008349FA13C0F90568193137484036AFA89044FA13C082EFAAC52F37484062BA10AB3FFA13C05F6CAD712E37484065F238D23AFA13C001035A1D2D3748403E57210636FA13C067B3B0C82B37484064B5754731FA13C020F7C6732A37484060408A952CFA13C00FDB711E2937484033F85EF027FA13C05152DCC827374840DCDCF35723FA13C057E3F072263748405BEE48CC1EFA13C0B107C51C2537484028F9094E1AFA13C0D04543C623374840CB308BDC15FA13C0B39D6B6F223748404495CC7711FA13C0E9885318213748400BF379200DFA13C07307FBC01F374840A87DE7D508FA13C0322637691E3748401B35159804FA13C0D35148111D374840DCE5AE6700FA13C0399703B91B37484073C30844FCF913C0F36F7E601A374840579ACE2DF8F913C07062A30719374840129E5424F4F913C0D0619DAE17374840A3CE9A27F0F913C0F57A41551637484081F84C38ECF913C06C27A5FB14374840364FBF55E8F913C03767C8A113374840389F9D80E4F913C0C7C0954712374840101C3CB8E0F913C0392738ED10374840BFC59AFCDCF913C0FE209A920F3748403235114FD9F913C016AEBB370E37484004059CADD5F913C0F35487DC0C3748409A9A3E1AD2F913C0B30828810B3748409090F592CEF913C054C99D250A3748404B4CC419CBF913C0BAA3BDC908374840DB3453ADC7F913C0028BB26D07374840424AA24DC4F913C00F8C5111063748406E2509FCC0F913C08C13DBB404374840F86084B6BDF913C0CFB40E58033748404762177FBAF913C0F36217FB013748406D906A54B7F913C0FA1DF59D00374840DFB72937B4F913C0546C9240FF364840280CA926B1F913C0014EEFE2FD364840BF599423AEF913C0913C2185FC364840A2A0EB2DABF913C002382827FB364840D4E0AE45A8F913C0C8C6EEC8F9364840DB4D326AA5F913C06F628A6AF836484030B4219CA2F913C0F90AFB0BF73648405B47D1DA9FF913C065C040ADF53648404AA098279DF913C02409464EF4364840102620819AF913C0C55E20EFF236484023A513E897F913C049C1CF8FF1364840841D735C95F913C03EAA6930F0364840BBC292DD92F913C08626C3D0EE3648403F611E6C90F913C0B0AFF170ED36484011F915088EF913C0BD45F510EC364840308A79B18BF913C0ACE8CDB0EA3648409C14496889F913C00C129150E93648405698842C87F913C0BFCE13F0E7364840E64880FD84F913C0E311818FE6364840C3F2E7DB82F913C079DBD82EE5364840EE95BBC780F913C06238F0CDE33648406632FBC07EF913C0BC1BF26CE23648402BC8A6C77CF913C0F80BC90BE13648403E57BEDB7AF913C0A5828AAADF364840271396FC78F913C035062149DE364840D594852B77F913C03610A2E7DC3648405943356775F913C01927F885DB364840A1B7FCB073F913C06DC43824DA364840', 'TRA', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (0, 'LOR', 'Worker smile spend parent certain tell dream. Small hope professor thus. Every nothing rest myself.', 'MED', '2022-05-10 12:23:59', NULL, NULL, 'KYL', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (14, 'MRS', 'Laugh surface few military current fine set. Wife list culture.', 'SA', '2022-03-12 03:48:14', '2022-05-15 03:13:36', NULL, 'MIC', false, NULL, 'MONITORENV', true, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (15, 'KAT', 'Population source pass recognize a modern. Might board take both century.', 'MEMN', '2022-01-21 18:52:58', '2022-02-20 20:37:16', NULL, 'AND', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (16, 'KAI', 'All serve try turn impact society.', 'SA', '2022-05-18 15:16:38', '2022-06-08 01:38:04', NULL, 'CAS', false, NULL, 'MONITORENV', true, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (17, 'KEL', 'Role from six under reveal. Suddenly surface give out. Doctor religious protect.', 'MED', '2022-06-08 02:30:39', '2022-08-06 08:55:19', NULL, 'GER', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (18, 'KEN', 'Upon specific director threat. Picture about some develop its Democrat. Anyone politics whatever morning program debate. Network your fear unit author stop.', 'SA', '2022-03-07 15:51:24', '2022-04-08 15:52:44', NULL, 'NIC', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (22, 'MAR', 'So maintain focus bag. Benefit put charge shake high national experience music. Surface computer decade happen small.', 'SA', '2022-03-24 15:31:07.588693', '2022-07-23 15:02:17.588693', '0106000020E61000000100000001030000000100000004000000ECDC6E9DB53710C0044FC86E756248405F4F142E01E80FC0BCE54742B4624840D6A83C6137F30FC060DA35A9045D4840ECDC6E9DB53710C0044FC86E75624840', 'CAL', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (28, 'TRO', 'Industry term former scene increase miss beyond. So deep scientist bit scientist idea situation. Produce old moment brother.', 'MED', '2022-03-16 17:30:11.588693', '2022-04-28 11:59:06.588693', NULL, 'ETH', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (29, 'JES', 'Over choose thus someone tend certainly. Keep here also.', 'NAMO', '2022-02-16 04:14:20.588693', '2022-07-06 03:22:32.588693', '0106000020E6100000010000000103000000010000000600000058B68D0A029303C0581E6D7459944740ABE688FD5F5503C07C7A43E610974740F3D72C1A072A03C0882CF356B3914740D7E4639FDE5603C0E0087123E58F47405AF109EBA2C903C098800E5AF490474058B68D0A029303C0581E6D7459944740', 'JIM', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (30, 'RIC', 'Between land style police. Law fine turn sign individual kitchen life. Tonight skin dog south charge.', 'MED', '2022-01-12 14:00:08.588693', '2022-01-16 00:27:04.588693', NULL, 'KAT', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (33, 'LUI', 'Check car charge say industry bed. Sign year that general.', 'NAMO', '2022-02-21 22:50:25.588693', '2022-07-12 23:31:59.588693', '0106000020E61000000100000001030000000100000004000000992B5E069D5FFABFD8A0A4D7DE27474024B03A9F54A3F9BF3040224BF32B474004F86B1CFE77F8BFE8F14452A1234740992B5E069D5FFABFD8A0A4D7DE274740', 'STE', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (36, 'MIC', 'Scientist cut scientist may interesting. Them energy teach reveal director way. History condition soldier because information first leg. Add thought one cell order.', 'MEMN', '2022-01-19 04:25:32.588693', '2022-04-20 06:14:10.588693', NULL, 'TRI', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (41, 'BRI', 'Magazine more morning we career born. Language notice site next history.', 'MEMN', '2022-07-01 00:44:16.588693', '2022-07-22 16:00:27.588693', NULL, 'MAR', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (1, 'RYA', 'Former wonder condition. Space student them investment good certainly effect.', 'MED', '2022-07-24 10:00:01', '2022-08-07 01:29:32', '0106000020E610000001000000010300000001000000C90000002EAED577FB6212C046D739EF7D2448405F559105FB6212C089E30E797D2448409230D9BFFA6212C04935A6027D2448407FDABEA6FA6212C0C9B61D8C7C2448405CA848BAFA6212C0385A93157C24484039A871FAFA6212C06D12259F7B24484013A22967FB6212C0EFCAF0287B2448401C1C5500FC6212C0CF6014B37A2448408961CDC5FC6212C0BF9AAD3D7A244840938C60B7FD6212C0DE21DAC879244840E292D1D4FE6212C0F579B75479244840F954D81D006312C02AFA62E178244840B4B02192016312C085C5F96E78244840ED954F31036312C0B0C398FD772448407C1EF9FA046312C086995C8D77244840CCA8AAEE066312C0D8A1611E77244840B7F4E50B096312C05EE6C3B076244840E84322520B6312C0A3189F4476244840177CCCC00D6312C0DE8A0EDA752448402F4C4757106312C01F292D71752448404354EB14136312C0AD72150A75244840BE4F07F9156312C00673E1A4742448402742E002196312C080BBAA41742448406AA6B1311C6312C0CE5C8AE0732448405DA0AD841F6312C08DE09881732448401731FDFA226312C04C43EE2473244840DA6CC093266312C043EEA1CA72244840F0B30E4E2A6312C063B1CA72722448405CEDF6282E6312C0D9BD7E1D72244840A5C37F23326312C03BA0D3CA7124484005E4A73C366312C0113BDE7A712448405B3F66733A6312C0A5C1B22D71244840054DAAC63E6312C006B364E370244840D94F5C35436312C0BCD4069C70244840D79C5DBE476312C0862EAB577024484073E388604C6312C05E05631670244840CD77B21A516312C054D73ED86F2448404E9EA8EB556312C075574E9D6F2448400ED933D25A6312C0A669A0656F2448404B3617CD5F6312C0DC1E43316F244840A2A010DB646312C0CDB143006F2448405F30D9FA696312C07083AED26E2448402F7E252B6F6312C0B8178FA86E24484096F6A56A746312C00413F0816E244840F42E07B8796312C00937DB5E6E244840343BF2117F6312C0BB60593F6E24484056040D77846312C0D48572236E244840F69FFAE5896312C0C9B22D0B6E24484064A85B5D8F6312C0370991F66D2448407B95CEDB946312C037BEA1E56D244840C715F05F9A6312C0041964D86D2448406B685BE89F6312C0F871DBCE6D24484047B7AA73A56312C09F310AC96D24484031717700AB6312C03CD0F1C66D244840C3A45A8DB06312C05FD592C86D244840C95AED18B66312C097D7ECCD6D2448401EF1C8A1BB6312C0E07CFED66D24484051758726C16312C0957AC5E36D244840CDFEC3A5C66312C06D963EF46D24484031091B1ECC6312C0FCA665086E2448403DCE2A8ED16312C0F39435206E244840F19E93F4D66312C03C5CA83B6E244840773CF84FDC6312C09F0DB75A6E2448408330FE9EE16312C078D0597D6E244840AF244EE0E66312C0CCE487A36E24484035399412EC6312C045A537CD6E244840015B8034F16312C0D3895EFA6E2448404198C644F66312C0462AF12A6F2448408E741F42FB6312C04141E35E6F244840893B482B006412C019AF27966F2448404A5203FF046412C0767DB0D06F244840BA8718BC096412C0ABE26E0E702448408C6355610E6412C07545534F702448404C738DED126412C0E1404D9370244840AA969A5F176412C0A8A84BDA7024484092495DB61B6412C02A8D3C2471244840D4ECBCF01F6412C069400D7171244840210DA80D246412C0405AAAC071244840FFA7140C286412C0C8BDFF1272244840216F00EB2B6412C0049EF86772244840730971A92F6412C06D837FBF72244840A5527446336412C020517E1973244840169820C1366412C0BC4ADE7573244840FED394183A6412C0E51988D47324484050E6F84B3D6412C033D46335742448402BCB7D5A406412C057015998742448406ACF5D43436412C02BA14EFD7424484048C2DC05466412C021322B6475244840422548A1486412C0AEB7D4CC75244840CE58F7144B6412C0A0C030377624484066C74B604D6412C0326E24A376244840420DB1824F6412C08D7A941077244840ED1D9D7B516412C0C03F657F772448405167904A536412C0BCBE7AEF77244840AEF115EF546412C06DA6B860782448406D7DC368566412C0CF5A02D378244840BD9D39B7576412C042FC3A4679244840E4D023DA586412C0B76E45BA79244840739538D1596412C02461042F7A244840FF7C399C5A6412C0F7545AA47A244840CD3BF33A5B6412C05CA5291A7B244840CAB53DAD5B6412C0D18E54907B244840B408FCF25B6412C0DB36BD067C24484092931C0C5C6412C019B3457D7C244840CFFA98F85B6412C06C11D0F37C2448403E2A76B85B6412C0FD5E3E6A7D2448408D53C44B5B6412C028B072E07D24484060EA9EB25A6412C0F9274F567E244840519D2CED596412C092FFB5CB7E2448402A4C9FFB586412C0D68D89407F2448405FFB33DE576412C0DF4EACB47F24484087C43295566412C06AEB00288024484060C4EE20556412C046406A9A802448408205C681536412C0C965CB0B81244840F26821B8516412C0DFB6077C812448404D8B74C44F6412C08ED802EB81244840E0A73DA74D6412C0F2C0A05882244840B37805614B6412C065BEC5C482244840D4135FF2486412C06A7E562F832448407AC6E75B466412C0C51438988324484001ED469E436412C0F90150FF83244840D4C82DBA406412C05C3A846484244840905357B03D6412C0522CBBC784244840B10F88813A6412C0FFC6DB288524484044D78D2E376412C06180CD87852448407BA73FB8336412C0DE5B78E4852448408B6A7D1F306412C0E8EFC43E8624484047BF2F652C6412C0476C9C968624484011BE478A286412C0889FE8EB862448401CBCBE8F246412C0FAFC933E87244840510C9676206412C0B1A1898E8724484078BED63F1C6412C01E5AB5DB87244840215C91EC176412C014A7032688244840BEA3DD7D136412C0AAC2616D882448402542DAF40E6412C005A5BDB188244840EA89AC520A6412C0D60806F3882448406E298098056412C0C66F2A318924484002DF86C7006412C0AD261B6C89244840E52BF8E0FB6312C06D49C9A3892448403D0511E6F66312C0CBC626D889244840418413D8F16312C0D86326098A244840D19446B8EC6312C082BFBB368A244840A7A2F587E76312C08F55DB608A244840F3457048E26312C0A0817A878A24484037EE09FBDC6312C0AB818FAA8A244840D08C19A1D76312C0A07811CA8A244840043EF93BD26312C0C770F8E58A244840D9F105CDCC6312C0625D3DFE8A244840C0139F55C76312C0C81CDA128B244840D13126D7C16312C0CF79C9238B2448406DA3FE52BC6312C0322D07318B244840902F8DCAB66312C078DE8F3A8B244840A4B2373FB16312C0152561408B244840EEC364B2AB6312C0AB8879428B244840375B7B25A66312C0D481D8408B244840E575E299A06312C0D6797E3B8B2448405CBC00119B6312C0D2CA6C328B24484063273C8C956312C06DBFA5258B24484089A5F90C906312C00B922C158B24484037C19C948A6312C00B6C05018B244840B2468724856312C0036535E98A244840B4EA18BE7F6312C0F980C2CD8A2448409AF1AE627A6312C05FAFB3AE8A24484033D7A313756312C0D8C8108C8A24484012F74ED26F6312C0A68DE2658A244840E33504A06A6312C02DA3323C8A2448408DAB137E656312C0B4910B0F8A244840494EC96D606312C089C178DE89244840AB9E6C705B6312C04F7886AA89244840FE544087566312C0CCD5417389244840970F82B3516312C0A0D0B83889244840CD026AF64C6312C0BD32FAFA88244840EDA92A51486312C0829515BA88244840BD79F0C4436312C01B5E1B7688244840D994E1523F6312C033B91C2F882448400B811DFC3A6312C075962BE587244840EBDEBCC1366312C044A45A9887244840CC22D1A4326312C0E04ABD4887244840B94F64A62E6312C0A0A767F6862448404EB478C72A6312C09F876EA1862448405DA90809276312C0A862E74986244840AD52066C236312C0E755E8EF85244840F3615BF11F6312C0F31D88938524484084DBE8991C6312C07D11DE3485244840D8DD8666196312C0191B02D4842448409C6A0458166312C04DB30C71842448408B32276F136312C084DA160C842448408163ABAC106312C078123AA583244840FB7843110E6312C01658903C83244840D90E989D0B6312C0821C34D282244840DCB64752096312C0F23E406682244840BED0E62F076312C04A05D0F8812448406164FF36056312C0B415FF898124484056FF1068036312C0696FE919812448404C9490C3016312C0A863ABA880244840BF5DE849006312C09E8E6136802448400EC377FBFE6212C0FBCF28C37F244840724093D8FD6212C0F5431E4F7F244840825184E1FC6212C0A73B5FDA7E244840DA5E8916FC6212C0CC3509657E2448402EAED577FB6212C046D739EF7D244840', 'VIC', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (9, 'CLI', 'Majority describe successful. Ahead standard language.', 'MEMN', '2022-03-10 08:20:51', '2022-06-30 10:54:47', '0106000020E6100000010000000103000000010000000C000000790D558C4ED911C0541F48DE393148404E9D47C5FFD511C0C498F4F7523048408B04AE861FD711C0F4D1F3B8B92F484004D149A58EDC11C0DFB76B53862F4840034A9E46B5DB11C073DBBE47FD2F48406286C61341DC11C0BCB1A030283048402C94F1947AE311C07CBF2C488E304840E2D92FE939E311C084921337B830484052F01472A5DE11C04969368FC33048408930348DDCD911C02F4FE78A5231484044D0E2D6EED811C06BF4C53945314840790D558C4ED911C0541F48DE39314840', 'TER', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (11, 'BRI', 'Example area order two watch travel little. Understand near they star.', 'MED', '2022-04-23 01:41:36', '2022-06-01 03:04:48', '0106000020E61000000100000001030000000100000009000000C520B072685114C08FC2F5285C2F4840B4C876BE9F1A14C00000000000384840F2D24D62109813C0F4FDD478E9364840EC51B81E856B13C03333333333334840EE7C3F355E3A13C0105839B4C82E4840A69BC420B03213C00C022B871629484048E17A14AE8713C0BA490C022B2748409CC420B072A813C02B8716D9CE274840C520B072685114C08FC2F5285C2F4840', 'KEV', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (8, 'NIC', 'Respond later simply discuss yet sport. Participant that together himself mother. Support happen girl clearly.', NULL, '2022-03-01 14:21:37', NULL, '0106000020E6100000010000000103000000010000000F000000EBBCD75AA9C911C09A65AABB0D3148406EE987C734C911C0BB54B6590631484014AEEC2708CB11C0089DC6ACCD3048407BE3FFE961CB11C052D1FD41C9304840363A8CEEC5CC11C096067E54C330484036B286E695CE11C0CA332F87DD30484024B149230BCD11C0DB9CEF4C0D314840E486DF4DB7CC11C02B1ECD470831484043531B41CFCB11C0FFC64384243148405C8FC2F528CC11C0BB078D052A3148403C5D273FF3CB11C005E91846303148403231A715F0CC11C021CB82893F314840D1820651ADCC11C07CE3B55C473148409B45DE2868C911C07E7B8D1315314840EBBCD75AA9C911C09A65AABB0D314840', 'YVO', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (6, 'MAU', 'Role morning option however bag rise check. Not among fill two blue crime. Across his score second knowledge yes.', NULL, '2022-06-13 16:10:59', NULL, '0106000020E61000000100000001030000000100000009000000BBF448E6051E12C03D29720C712E48407BB33829ED1D12C09F2D31E0762E4840866B9CEA1C1D12C0CAF2E0B4812E48409763471DFC1C12C0714A0E12812E48406C672D3F4F1B12C041857E01982E484057D0308C261912C046521C516B2E484098E4DB16C01B12C02FDA25A2462E48408E601DA6011C12C0D5FA6C2E482E4840BBF448E6051E12C03D29720C712E4840', 'KEL', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (7, 'MIC', 'Cultural staff letter give. Agency that poor third positive red capital particularly. May whether clear any someone picture bit.', 'NAMO', '2022-08-07 00:25:12', NULL, '0106000020E610000001000000010300000001000000050000005B8E5F91C27512C0B72D4634EC2A4840DDC5871BE87412C0A7348BE5D02A4840A74BB5053A6D12C00CC050D1222B4840AD7BD8C9E86D12C0B34C54A9382B48405B8E5F91C27512C0B72D4634EC2A4840', 'ROB', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (2, 'LUK', 'Attack him company article their everybody.', 'SA', '2022-05-22 10:04:10', '2022-08-06 06:23:21', '0106000020E61000000100000001030000000100000005000000FEEA55BCF63312C0BD25582F0A274840E62E16E75B3312C0AA6C84AA2127484019F3D214263212C08075CE591327484031A51A8BBF3212C0B47A13E9FB264840FEEA55BCF63312C0BD25582F0A274840', 'JES', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (3, 'HEA', 'Heavy reach forget positive business theory level. Plan loss or administration PM shoulder such.', 'NAMO', '2022-07-06 15:20:35', '2022-08-10 07:11:32', '0106000020E610000001000000010300000001000000050000008F4568E7F23112C0B64707961C274840102400352C3312C02DC0D2382A27484058877C452F3312C0961FACF1512748405D7025C4F63112C09AC9FA63442748408F4568E7F23112C0B64707961C274840', 'WIL', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (4, 'JAN', 'It loss often we stock light.', 'SA', '2022-01-04 10:54:00', '2022-04-20 09:01:52', '0106000020E61000000100000001030000000100000007000000C83922FC691F12C0858E1AB73F2E4840345DFE148E1E12C047759E08632E48403CDA29BF131E12C0CCF0FB66672E4840C4E38C74521C12C0F74063E7432E4840F6EBF44B501C12C0395A33E53E2E484093AC724D1A1E12C01D5DC3F4252E4840C83922FC691F12C0858E1AB73F2E4840', 'SCO', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (5, 'MAR', 'Reduce strategy indicate care population billion third.', 'NAMO', '2022-08-07 23:01:09', '2022-08-10 04:29:28', '0106000020E6100000010000000103000000010000000600000056AB6382071313C00C022B87163148404EC5D987CF1013C00C022B87163148408FE4F21FD20F13C069F188F7093148408FE4F21FD20F13C070BFA248E430484056AB6382071313C070BFA248E430484056AB6382071313C00C022B8716314840', 'JOR', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (44, 'JAI', 'Believe single player sister risk. Fly himself word actually. Particular matter during feel.', 'NAMO', '2022-01-14 19:20:36.588693', '2022-03-20 09:02:35.588693', NULL, 'STE', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (24, 'KAR', 'Machine office recently answer dark such toward west. Around tree green management opportunity central then. Can time into magazine.', 'MEMN', '2022-06-27 06:09:45.588693', '2022-07-03 01:03:07.588693', NULL, 'JAM', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (23, 'KIM', 'Become knowledge can effect foreign article citizen. Upon well war coach.', 'NAMO', '2022-04-29 01:55:27.588693', NULL, NULL, 'KEV', false, NULL, 'MONITORENV', false, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (26, 'KAT', 'Me low southern Congress. Describe dog teach land else. Bed grow practice adult several information.', 'SA', '2022-01-02 17:47:34.588693', '2022-04-29 00:21:03.588693', NULL, 'PAT', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (21, 'HUN', 'Attack kind marriage.', 'MED', '2022-03-04 00:51:26.588693', NULL, NULL, 'MR.', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (32, 'COR', 'Rest whom analysis activity party. Camera right find soon.', 'NAMO', '2022-02-24 16:10:01.588693', '2022-03-01 22:08:38.588693', NULL, 'CHA', false, NULL, 'MONITORENV', true, NULL, '{AIR}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (42, 'KYL', 'Bring speech them spring. Whether life green loss career become save. On force debate study option push. Research appear who lawyer likely degree.', 'NAMO', '2022-04-28 02:15:59.588693', NULL, NULL, 'MR.', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (31, 'WES', 'Vote to perhaps room improve process. Four near prepare election worry Democrat step. Quality fear fire international.', 'NAMO', '2022-02-08 22:47:02.588693', NULL, NULL, 'LAU', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (37, 'DAV', 'Light drive hour ground foot fly eat all. Anything talk condition movement task company nearly seven. Analysis necessary far system. Rule within natural pay seek employee fund.', 'NAMO', '2022-02-24 13:22:25.588693', NULL, NULL, 'DWA', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (45, 'BRI', 'Maybe own each college away likely major. Former space technology million cell. Outside body my drop require.', 'MEMN', '2022-06-04 16:25:52.588693', '2022-06-07 14:21:42.588693', NULL, 'SAM', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (48, 'CHA', 'Fly chance record lawyer those. Once position indicate war medical through. Interest read possible.', 'SA', '2022-06-25 11:29:31.588693', NULL, NULL, 'MAT', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (46, 'JOS', 'And without trip key. New head director return art explain edge. Wait civil community mission attorney partner. Month cold try message.', 'SA', '2022-03-17 23:16:22.588693', NULL, NULL, 'ANN', false, NULL, 'MONITORENV', false, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (43, 'DAR', 'Anything box film quality. Lot series agent out rule end young pressure.', 'MED', '2022-07-19 10:41:11.588693', '2022-07-26 21:21:57.015651', '0106000020E610000001000000010300000001000000060000004AF3CFCF7C9510C0348D456F648348404F7336C598DB0EC0481B7432AC424840CB21CD9B29570CC0DC97C7300F7648406C117FC670E60EC03C0D98345E934840F63ACBC2ED5F10C030BA1A4F249748404AF3CFCF7C9510C0348D456F64834840', 'HEI', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (34, 'STS', 'Surface different shoulder interview. Job together area probably. Of alone class capital determine machine always.', 'MEMN', '2022-07-15 21:03:12.588693', '2022-07-16 22:03:12.588693', '0106000020E61000000100000001030000000100000009000000AD0812BCE168E4BFCCDEEA3227BD4840BE63AEABD812E4BF1C5E8873F8AC484044BD156CA117DABF84C0E2AF49AC48408E16A14DE463CCBFBC9F7168A2A5484008BF4C12D0F97B3F9494F5EA3CAB4840399BF9438A28B43FDC4BF050D9BB48404BAA02B73C2CCCBF24A79C8362CD4840BC46F7A9D24DE1BFA0238D36B2D04840AD0812BCE168E4BFCCDEEA3227BD4840', 'JAM', false, NULL, 'MONITORENV', false, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (47, 'CHR', 'Decision about effect sport hour field. Care finally minute stop.', 'SA', '2022-05-11 02:03:23.588693', '2022-05-13 04:47:02.588693', NULL, 'AMA', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (49, 'MIC', 'Check environment role actually whether majority blood. And action section bag middle. Somebody main stage sense.', NULL, '2022-07-28 21:54:28.588693', '2022-08-02 22:46:19.588693', '0106000020E610000001000000010300000001000000070000006A4B99E0A2F609C0F0BCE41CA7D44740A141A028CD9C09C0E0C13397F4D04740679BDF9ADA9809C0A8D2BC3DA7CF4740A669A645F8AF09C0E8FD4743E9CD47402853A486852D0AC0E059C31BBED34740D495265101290AC0CCE7F9B8F6D447406A4B99E0A2F609C0F0BCE41CA7D44740', 'MIC', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (38, 'RAN', 'Black bit sell. House relate policy once. White member worker east even anyone detail professor.', NULL, '2022-07-29 10:53:31.588693', '2022-07-31 14:24:31.858651', '0106000020E61000000300000001030000000100000005000000E1AC900B314306C0DCABC1C17F1C484077EC6F225D5006C0E9C04905DB0A4840C4FDB241475F05C0D322916C64104840C4FDB241475F05C061C3D32BE51E4840E1AC900B314306C0DCABC1C17F1C4840010300000001000000050000001A381C6D873C05C0857E01182A1748407A5824FD283005C06AB86D846A13484012C925C8E7D104C048BD6DC7D014484056F6FAE640DF04C04921B9CACD1748401A381C6D873C05C0857E01182A17484001030000000100000005000000BA44FD4709AE06C0BD44AB4926174840374C3CB9097B06C0416F22E1981148409F7BAC6C615606C0DA75EB0C3E164840F5F0C8CCC36906C01B578E56561A4840BA44FD4709AE06C0BD44AB4926174840', 'TIM', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (25, 'KEV', 'Toward agency blue now hand. Meet answer someone stand.', 'MED', '2022-06-04 20:01:28.588693', '2022-06-30 05:17:45.588693', NULL, 'CYN', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (27, 'BON', 'Out born Republican owner real case. Almost south seven service education push. Too step pay her.', 'NAMO', '2022-01-14 09:37:59.588693', '2022-05-25 09:51:46.588693', NULL, 'SCO', false, NULL, 'MONITORENV', true, NULL, '{SEA}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (35, 'SAM', 'Beyond such seven let break enter. Perform lose seem soldier study imagine. Always space concern stop. Value today you look ahead before.', 'MED', '2022-02-23 05:35:44.588693', '2022-05-11 01:04:42.588693', NULL, 'JOH', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (39, 'KEI', 'Without black box common. More reduce many trial.', 'MED', '2022-03-02 05:42:47.588693', '2022-05-03 09:16:22.588693', NULL, 'ELI', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (40, 'TAM', 'Idea tonight interesting value.', 'NAMO', '2022-03-17 13:29:55.588693', '2022-05-27 02:14:48.588693', NULL, 'RAN', false, NULL, 'MONITORENV', true, NULL, '{LAND}'); -INSERT INTO public.missions (id, open_by, observations_cacem, facade, start_datetime_utc, end_datetime_utc, geom, closed_by, deleted, observations_cnsp, mission_source, closed, mission_order, mission_types) VALUES (53, 'CDA', 'Idea tonight interesting value.', 'NAMO', '2022-11-21 13:29:55.588693', '2022-11-23 02:14:48.588693', NULL, 'CDA', false, NULL, 'MONITORENV', false, NULL, '{LAND, SEA}'); - - -SELECT pg_catalog.setval('public.missions_id_seq', 53, true); - -INSERT INTO missions_control_units - (mission_id, control_unit_id) -VALUES - ( 0, 10002), - ( 1, 10080), - ( 2, 10002), - ( 3, 10004), - ( 4, 10003), - ( 5, 10003), - ( 6, 10002), - ( 7, 10002), - ( 8, 10018), - ( 9, 10018), - ( 10, 10002), - ( 11, 10022), - ( 12, 10018), - ( 12, 10017), - ( 13, 10018), - ( 14, 10002), - ( 15, 10003), - ( 16, 10019), - ( 17, 10003), - ( 18, 10003), - ( 19, 10018), - ( 20, 10002), - ( 21, 10018), - ( 22, 10121), - ( 23, 10121), - ( 24, 10000), - ( 26, 10080), - ( 27, 10003), - ( 28, 10019), - ( 29, 10018), - ( 30, 10000), - ( 30, 10002), - ( 31, 10003), - ( 32, 10003), - ( 33, 10002), - ( 35, 10003), - ( 36, 10002), - ( 37, 10003), - ( 38, 10002), - ( 39, 10003), - ( 40, 10003), - ( 41, 10002), - ( 42, 10003), - ( 44, 10003), - ( 45, 10014), - ( 46, 10018), - ( 48, 10080), - ( 49, 10002), - ( 50, 10002), - ( 51, 10002), - ( 51, 10002); - -INSERT INTO missions_control_units - (mission_id, control_unit_id, contact) -VALUES - ( 34, 10015, '01234567890'), - ( 34, 10016, 'M. Capitaine Flame'), - ( 34, 10017, 'Popeye 06789012345'), - ( 47, 10002, 'A Team - Gimme your number'), - ( 25, 10002, 'Full contact'), - ( 43, 10018, 'Full contact'), - ( 53, 10018, 'Full contact'); - -INSERT INTO missions_control_resources - (mission_id, control_resource_id) -VALUES - ( 10, 3), - ( 10, 4), - ( 10, 5), - ( 12, 10), - ( 13, 8), - ( 14, 3), - ( 15, 6), - ( 17, 7), - ( 6, 3), - ( 7, 3), - ( 2, 3), - ( 24, 1), - ( 23, 8), - ( 26, 12), - ( 21, 10), - ( 42, 6), - ( 30, 13), - ( 31, 6), - ( 37, 6), - ( 48, 12), - ( 46, 12), - ( 43, 8), - ( 34, 11), - ( 25, 3), - ( 39, 7), - ( 40, 7), - ( 53, 8); - -UPDATE public.missions SET - start_datetime_utc = start_datetime_utc + (now() - '2022-06-01 23:00:00'), - end_datetime_utc = end_datetime_utc + (now() - '2022-06-01 23:00:00') -WHERE id > 20; diff --git a/backend/src/main/resources/db/testdata/V666.6__insert_dummy_env_actions.sql b/backend/src/main/resources/db/testdata/V666.6__insert_dummy_env_actions.sql deleted file mode 100644 index 32573d34c7..0000000000 --- a/backend/src/main/resources/db/testdata/V666.6__insert_dummy_env_actions.sql +++ /dev/null @@ -1,28 +0,0 @@ --- --- Data for Name: env_actions; Type: TABLE DATA; Schema: public; Owner: postgres --- -DELETE FROM public.env_actions; - -INSERT INTO public.env_actions VALUES ('e2257638-ddef-4611-960c-7675a3254c38', 38, 'SURVEILLANCE', '{"themes": [{"theme": "Police des activités de cultures marines", "subThemes": ["Contrôle du schéma des structures"], "protectedSpecies": []}], "observations": "", "coverMissionZone": true}', '2022-07-30 08:53:31.588693', NULL, NULL, '56', '2022-07-30 10:53:31.588693'); -INSERT INTO public.env_actions VALUES ('f3e90d3a-6ba4-4bb3-805e-d391508aa46d', 38, 'CONTROL', '{"themes": [{"theme": "Police des épaves", "subThemes": ["Épave/navire abandonné", "Contrôle administratif"], "protectedSpecies": []}], "infractions": [{"id": "6670e718-3ecd-46c1-8149-8b963c6f72dd", "natinf": ["10041"], "toProcess": false, "vesselSize": null, "vesselType": null, "companyName": "MASOCIETE", "formalNotice": "YES", "observations": "RAS", "relevantCourt": "LOCAL_COURT", "infractionType": "WITH_REPORT", "registrationNumber": null, "controlledPersonIdentity": null}], "vehicleType": null, "observations": null, "actionTargetType": "COMPANY", "actionNumberOfControls": 1}', '2022-07-29 11:53:31.588693', '0104000020E6100000010000000101000000399291D4BE1805C09E1A585CD6154840', NULL, NULL, NULL); - -INSERT INTO public.env_actions VALUES ('475d2887-5344-46cd-903b-8cb5e42f9a9c', 49, 'SURVEILLANCE', '{"themes": [{"theme": "Police du conservatoire du littoral", "subThemes": ["Réglementation du conservatoire du littoral"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": false, "protectedSpecies": []}', NULL, '0106000020E61000000100000001030000000100000005000000D56979C3E95203C0BC117648B972474084387273B24D02C00C726AA38C6E4740BFFBD6B9762002C0349A2D10497347407A8D399212A102C0546E1659817A4740D56979C3E95203C0BC117648B9724740'); -INSERT INTO public.env_actions VALUES ('16eeb9e8-f30c-430e-b36b-32b4673f81ce', 49, 'NOTE', '{"observations": "Note libre"}', NULL, NULL); -INSERT INTO public.env_actions VALUES ('6d4b7d0a-79ce-47cf-ac26-2024d2b27f28', 49, 'CONTROL', '{"themes": [{"theme": "AMP sans réglementation particulière", "subThemes": ["Contrôle dans une AMP sans réglementation particulière"], "protectedSpecies": []}], "infractions": [{"id": "e56648c1-6ca3-4d5e-a5d2-114aa7c17126", "natinf": ["10231", "10228"], "toProcess": true, "vesselSize": null, "vesselType": null, "companyName": null, "formalNotice": "PENDING", "observations": "RAS", "relevantCourt": "PRE", "infractionType": "WAITING", "registrationNumber": null, "controlledPersonIdentity": "M DURAND"}], "vehicleType": null, "actionTargetType": "INDIVIDUAL", "actionNumberOfControls": 1}', NULL, '0104000020E61000000100000001010000003B0DADC6D4BB01C0A8387A2964714740'); - -INSERT INTO public.env_actions VALUES ('c52c6f20-e495-4b29-b3df-d7edfb67fdd7', 34, 'SURVEILLANCE', '{"themes": [{"theme": "Police des espèces protégées et de leurs habitats (faune et flore)", "subThemes": ["Destruction, capture, arrachage", "Atteinte aux habitats d''espèces protégées"], "protectedSpecies": ["FLORA", "BIRDS"]}, {"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": true, "protectedSpecies": []}', '2022-07-16 10:03:12.588693', NULL, NULL, NULL, '2022-07-16 12:03:12.588693'); -INSERT INTO public.env_actions VALUES ('b8007c8a-5135-4bc3-816f-c69c7b75d807', 34, 'CONTROL', '{"themes": [{"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "observations": "RAS", "infractions": [{"id": "5d5b7829-68cd-4436-8c0b-1cc8db7788a0", "natinf": ["10038","10231"], "toProcess": false, "vesselSize": "FROM_24_TO_46m", "vesselType": "COMMERCIAL", "companyName": null, "formalNotice": "PENDING", "observations": "Pas d''observations", "relevantCourt": "LOCAL_COURT", "infractionType": "WITH_REPORT", "registrationNumber": "BALTIK", "controlledPersonIdentity": "John Doe"}], "vehicleType": "VESSEL", "actionTargetType": "VEHICLE", "actionNumberOfControls": 1}', '2022-07-16 09:03:12.588693', '0104000020E610000001000000010100000047A07E6651E3DEBF044620AB65C54840', NULL, NULL, '2022-07-16 12:03:12.588693'); - -INSERT INTO public.env_actions VALUES ('4d9a3139-6c60-49a5-b443-0e6238a6a120', 41, 'CONTROL', '{"themes": [{"theme": "Police des mouillages", "subThemes": ["Contrôle administratif"], "protectedSpecies": []}], "infractions": [], "vehicleType": null, "observations": "", "actionTargetType": null, "actionNumberOfControls": null}','2022-07-01 02:44:16.588693', NULL, NULL, NULL, NULL, TRUE, TRUE, TRUE, TRUE); - - -INSERT INTO public.env_actions VALUES ('2cdcd429-19ab-45ed-a892-7c695bd256e2', 53, 'SURVEILLANCE', '{"themes": [{"theme": "Pêche de loisir", "subThemes": ["Pêche embarquée"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": true, "protectedSpecies": []}', '2022-11-21 14:29:55.588693', NULL, NULL, NULL, '2022-11-22 12:14:48.588693'); -INSERT INTO public.env_actions VALUES ('3480657f-7845-4eb4-aa06-07b174b1da45', 53, 'CONTROL', '{"themes": [{"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "observations": "RAS", "infractions": [], "vehicleType": "VESSEL", "actionTargetType": "VEHICLE", "actionNumberOfControls": 0}', '2022-11-22 10:14:48.588693', '0104000020E610000001000000010100000047A07E6651E3DEBF044620AB65C54840', NULL, NULL, NULL); -INSERT INTO public.env_actions VALUES ('9969413b-b394-4db4-985f-b00743ffb833', 53, 'SURVEILLANCE', '{"themes": [{"theme": "Police des espèces protégées et de leurs habitats (faune et flore)", "subThemes": ["Destruction, capture, arrachage", "Atteinte aux habitats d''espèces protégées"], "protectedSpecies": ["FLORA", "BIRDS"]}, {"theme": "Police des mouillages", "subThemes": ["Mouillage individuel", "ZMEL"], "protectedSpecies": []}], "duration": 0.0, "observations": "RAS", "coverMissionZone": true, "protectedSpecies": []}', '2022-11-21 15:29:55.588693', NULL, NULL, NULL, '2022-11-22 13:14:48.588693'); - - -UPDATE public.env_actions SET - action_start_datetime_utc = action_start_datetime_utc + (now() - '2022-06-01 23:00:00'), - action_end_datetime_utc = action_end_datetime_utc + (now() - '2022-06-01 23:00:00') - WHERE mission_id > 20; - ; \ No newline at end of file diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/CreateOrUpdateReportingUTests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/CreateOrUpdateReportingUTests.kt index 53b2406a75..ca22118514 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/CreateOrUpdateReportingUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/CreateOrUpdateReportingUTests.kt @@ -81,8 +81,8 @@ class CreateOrUpdateReportingUTests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -104,8 +104,8 @@ class CreateOrUpdateReportingUTests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -126,8 +126,8 @@ class CreateOrUpdateReportingUTests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -149,8 +149,8 @@ class CreateOrUpdateReportingUTests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -241,8 +241,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -287,8 +287,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -333,8 +333,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -354,8 +354,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -373,8 +373,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -449,8 +449,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, @@ -478,8 +478,8 @@ class CreateOrUpdateReportingUTests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 1, + subThemeIds = listOf(10, 11), actionTaken = "actions effectuées blabal ", isControlRequired = true, hasNoUnitAvailable = true, diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansByYearUTest.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansByYearUTest.kt new file mode 100644 index 0000000000..b537b15a1a --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansByYearUTest.kt @@ -0,0 +1,77 @@ +package fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan + +import com.nhaarman.mockitokotlin2.given +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanTagRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanThemeRepository +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.context.junit.jupiter.SpringExtension + +@ExtendWith(SpringExtension::class) +class GetControlPlansByYearUTest { + @MockBean private lateinit var controlPlanSubThemeRepository: IControlPlanSubThemeRepository + private lateinit var controlPlanThemeRepository: IControlPlanThemeRepository + private lateinit var controlPlanTagRepository: IControlPlanTagRepository + + fun `execute should return all ControlPlanThemes, ControlPlanSubThemes and ControlPlanTags for the given year`() { + val controlPlanThemes = + listOf( + ControlPlanThemeEntity( + id = 1, + theme = "ControlPlanTheme Name", + ), + ControlPlanThemeEntity( + id = 2, + theme = "ControlPlanTheme Name 2", + ), + ) + val controlPlanSubThemes = + listOf( + ControlPlanSubThemeEntity( + id = 1, + themeId = 1, + subTheme = "ControlPlanSubTheme Name", + year = 2023, + ), + ControlPlanSubThemeEntity( + id = 2, + themeId = 1, + subTheme = "ControlPlanSubTheme Name 2", + year = 2023, + ), + ) + val controlPlanTags = + listOf( + ControlPlanTagEntity( + id = 1, + tag = "ControlPlanTag Name", + themeId = 1, + ), + ControlPlanTagEntity( + id = 2, + tag = "ControlPlanTag Name 2", + themeId = 2, + ), + ) + + given(controlPlanThemeRepository.findByYear(2023)).willReturn(controlPlanThemes) + given(controlPlanSubThemeRepository.findByYear(2023)).willReturn(controlPlanSubThemes) + given(controlPlanTagRepository.findByYear(2023)).willReturn(controlPlanTags) + + val result = + GetControlPlansByYear( + controlPlanThemeRepository = controlPlanThemeRepository, + controlPlanSubThemeRepository = controlPlanSubThemeRepository, + controlPlanTagRepository = controlPlanTagRepository, + ) + .execute(2023) + + assertThat(result.first.size).isEqualTo(2) + assertThat(result).isEqualTo(controlPlanSubThemes) + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansUTest.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansUTest.kt new file mode 100644 index 0000000000..049ee669c2 --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlPlan/GetControlPlansUTest.kt @@ -0,0 +1,73 @@ +package fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan + +import com.nhaarman.mockitokotlin2.given +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanSubThemeRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanTagRepository +import fr.gouv.cacem.monitorenv.domain.repositories.IControlPlanThemeRepository +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.context.junit.jupiter.SpringExtension + +@ExtendWith(SpringExtension::class) +class GetControlPlansUTest { + @MockBean + private lateinit var controlPlanSubThemeRepository: IControlPlanSubThemeRepository + private lateinit var controlPlanThemeRepository: IControlPlanThemeRepository + private lateinit var controlPlanTagRepository: IControlPlanTagRepository + + fun `execute should return all ControlPlanThemes, ControlPlanSubThemes and ControlPlanTags`() { + val controlPlanThemes = listOf( + ControlPlanThemeEntity( + id = 1, + theme = "ControlPlanTheme Name", + ), + ControlPlanThemeEntity( + id = 2, + theme = "ControlPlanTheme Name 2", + ), + ) + val controlPlanSubThemes = listOf( + ControlPlanSubThemeEntity( + id = 1, + themeId = 1, + subTheme = "ControlPlanSubTheme Name", + year = 2023, + ), + ControlPlanSubThemeEntity( + id = 2, + themeId = 1, + subTheme = "ControlPlanSubTheme Name 2", + year = 2023, + ), + ) + val controlPlanTags = listOf( + ControlPlanTagEntity( + id = 1, + tag = "ControlPlanTag Name", + themeId = 1, + ), + ControlPlanTagEntity( + id = 2, + tag = "ControlPlanTag Name 2", + themeId = 2, + ), + ) + + given(controlPlanThemeRepository.findAll()).willReturn(controlPlanThemes) + given(controlPlanSubThemeRepository.findAll()).willReturn(controlPlanSubThemes) + given(controlPlanTagRepository.findAll()).willReturn(controlPlanTags) + + val result = GetControlPlans( + controlPlanThemeRepository = controlPlanThemeRepository, + controlPlanSubThemeRepository = controlPlanSubThemeRepository, + controlPlanTagRepository = controlPlanTagRepository, + ).execute() + + assertThat(result.first.size).isEqualTo(2) + assertThat(result).isEqualTo(controlPlanSubThemes) + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlUnit/CanDeleteControlUnitUTests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlUnit/CanDeleteControlUnitUTests.kt index 68ce74a0f0..7b2dc1e625 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlUnit/CanDeleteControlUnitUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/controlUnit/CanDeleteControlUnitUTests.kt @@ -90,8 +90,8 @@ class CanDeleteControlUnitUTests { seaFront = null, description = null, reportType = null, - theme = null, - subThemes = null, + themeId = null, + subThemeIds = null, actionTaken = null, isControlRequired = null, hasNoUnitAvailable = null, diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/GetMissionsUTests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/GetMissionsUTests.kt index c68c39b836..dcc399ea3c 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/GetMissionsUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/GetMissionsUTests.kt @@ -1,18 +1,18 @@ package fr.gouv.cacem.monitorenv.domain.use_cases.missions +import com.nhaarman.mockitokotlin2.anyOrNull import com.nhaarman.mockitokotlin2.given -import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity -import fr.gouv.cacem.monitorenv.domain.repositories.IMissionRepository import fr.gouv.cacem.monitorenv.domain.entities.controlUnit.LegacyControlUnitEntity -import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum -import java.time.ZonedDateTime +import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum +import fr.gouv.cacem.monitorenv.domain.repositories.IMissionRepository import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.test.context.junit.jupiter.SpringExtension -import com.nhaarman.mockitokotlin2.anyOrNull +import java.time.ZonedDateTime @ExtendWith(SpringExtension::class) class GetMissionsUTests { @@ -20,27 +20,27 @@ class GetMissionsUTests { private lateinit var missionRepository: IMissionRepository private val controlUnit1: LegacyControlUnitEntity = LegacyControlUnitEntity( - id = 1, - administration = "whatever", - isArchived = false, - name = "whatever", - resources = listOf(), + id = 1, + administration = "whatever", + isArchived = false, + name = "whatever", + resources = listOf(), ) private val controlUnit2: LegacyControlUnitEntity = LegacyControlUnitEntity( - id = 2, - administration = "whatever", - isArchived = false, - name = "whatever", - resources = listOf(), + id = 2, + administration = "whatever", + isArchived = false, + name = "whatever", + resources = listOf(), ) private val controlUnit3: LegacyControlUnitEntity = LegacyControlUnitEntity( - id = 3, - administration = "whatever", - isArchived = false, - name = "whatever", - resources = listOf(), + id = 3, + administration = "whatever", + isArchived = false, + name = "whatever", + resources = listOf(), ) private val mission1 = @@ -54,7 +54,7 @@ class GetMissionsUTests { hasMissionOrder = false, isUnderJdp = false, isGeometryComputedFromControls = false, - controlUnits = listOf(controlUnit1, controlUnit2) + controlUnits = listOf(controlUnit1, controlUnit2), ) private val mission2 = @@ -68,23 +68,25 @@ class GetMissionsUTests { hasMissionOrder = false, isUnderJdp = false, isGeometryComputedFromControls = false, - controlUnits = listOf(controlUnit1, controlUnit3) + controlUnits = listOf(controlUnit1, controlUnit3), ) @Test fun `execute should return all missions when filter for controlUnits is null`() { - given(missionRepository.findAll( - startedAfter = anyOrNull(), - startedBefore = anyOrNull(), - missionSources = anyOrNull(), - missionTypes = anyOrNull(), - missionStatuses = anyOrNull(), - seaFronts = anyOrNull(), - pageable = anyOrNull(), - )).willReturn(listOf(mission1, mission2)) + given( + missionRepository.findAll( + startedAfter = anyOrNull(), + startedBefore = anyOrNull(), + missionSources = anyOrNull(), + missionTypes = anyOrNull(), + missionStatuses = anyOrNull(), + seaFronts = anyOrNull(), + pageable = anyOrNull(), + ), + ).willReturn(listOf(mission1, mission2)) val result = GetMissions(missionRepository).execute( - controlUnits = null + controlUnits = null, ) assertThat(result.size).isEqualTo(2) @@ -92,18 +94,20 @@ class GetMissionsUTests { @Test fun `execute should return all missions when filter for controlUnits is an empty list`() { - given(missionRepository.findAll( - startedAfter = anyOrNull(), - startedBefore = anyOrNull(), - missionSources = anyOrNull(), - missionTypes = anyOrNull(), - missionStatuses = anyOrNull(), - seaFronts = anyOrNull(), - pageable = anyOrNull(), - )).willReturn(listOf(mission1, mission2)) + given( + missionRepository.findAll( + startedAfter = anyOrNull(), + startedBefore = anyOrNull(), + missionSources = anyOrNull(), + missionTypes = anyOrNull(), + missionStatuses = anyOrNull(), + seaFronts = anyOrNull(), + pageable = anyOrNull(), + ), + ).willReturn(listOf(mission1, mission2)) val result = GetMissions(missionRepository).execute( - controlUnits = listOf() + controlUnits = listOf(), ) assertThat(result.size).isEqualTo(2) @@ -111,18 +115,20 @@ class GetMissionsUTests { @Test fun `execute should only one missions when the controlUnits input matches 1 mission`() { - given(missionRepository.findAll( - startedAfter = anyOrNull(), - startedBefore = anyOrNull(), - missionSources = anyOrNull(), - missionTypes = anyOrNull(), - missionStatuses = anyOrNull(), - seaFronts = anyOrNull(), - pageable = anyOrNull(), - )).willReturn(listOf(mission1, mission2)) + given( + missionRepository.findAll( + startedAfter = anyOrNull(), + startedBefore = anyOrNull(), + missionSources = anyOrNull(), + missionTypes = anyOrNull(), + missionStatuses = anyOrNull(), + seaFronts = anyOrNull(), + pageable = anyOrNull(), + ), + ).willReturn(listOf(mission1, mission2)) val result = GetMissions(missionRepository).execute( - controlUnits = listOf(controlUnit2.id) + controlUnits = listOf(controlUnit2.id), ) assertThat(result.size).isEqualTo(1) @@ -131,18 +137,20 @@ class GetMissionsUTests { @Test fun `execute should only two missions when the same controlUnits input matches 2 missions`() { - given(missionRepository.findAll( - startedAfter = anyOrNull(), - startedBefore = anyOrNull(), - missionSources = anyOrNull(), - missionTypes = anyOrNull(), - missionStatuses = anyOrNull(), - seaFronts = anyOrNull(), - pageable = anyOrNull(), - )).willReturn(listOf(mission1, mission2)) + given( + missionRepository.findAll( + startedAfter = anyOrNull(), + startedBefore = anyOrNull(), + missionSources = anyOrNull(), + missionTypes = anyOrNull(), + missionStatuses = anyOrNull(), + seaFronts = anyOrNull(), + pageable = anyOrNull(), + ), + ).willReturn(listOf(mission1, mission2)) val result = GetMissions(missionRepository).execute( - controlUnits = listOf(controlUnit1.id) + controlUnits = listOf(controlUnit1.id), ) assertThat(result.size).isEqualTo(2) @@ -150,21 +158,22 @@ class GetMissionsUTests { @Test fun `execute should return filtered missions matching multiple controlUnits input`() { - given(missionRepository.findAll( - startedAfter = anyOrNull(), - startedBefore = anyOrNull(), - missionSources = anyOrNull(), - missionTypes = anyOrNull(), - missionStatuses = anyOrNull(), - seaFronts = anyOrNull(), - pageable = anyOrNull(), - )).willReturn(listOf(mission1, mission2)) + given( + missionRepository.findAll( + startedAfter = anyOrNull(), + startedBefore = anyOrNull(), + missionSources = anyOrNull(), + missionTypes = anyOrNull(), + missionStatuses = anyOrNull(), + seaFronts = anyOrNull(), + pageable = anyOrNull(), + ), + ).willReturn(listOf(mission1, mission2)) val result = GetMissions(missionRepository).execute( - controlUnits = listOf(controlUnit2.id, controlUnit3.id) + controlUnits = listOf(controlUnit2.id, controlUnit3.id), ) assertThat(result.size).isEqualTo(2) } - } diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/TestUtils.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/TestUtils.kt index f24c94dfb1..a4a01f5e2c 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/TestUtils.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/domain/use_cases/missions/TestUtils.kt @@ -29,8 +29,8 @@ object TestUtils { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -65,8 +65,8 @@ object TestUtils { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlPlansControllerITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlPlansControllerITests.kt new file mode 100644 index 0000000000..c6a0a9b2d7 --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ControlPlansControllerITests.kt @@ -0,0 +1,137 @@ +package fr.gouv.cacem.monitorenv.infrastructure.api.endpoints.bff + +import com.nhaarman.mockitokotlin2.verify +import fr.gouv.cacem.monitorenv.config.WebSecurityConfig +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanSubThemeEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanTagEntity +import fr.gouv.cacem.monitorenv.domain.entities.controlPlan.ControlPlanThemeEntity +import fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan.GetControlPlans +import fr.gouv.cacem.monitorenv.domain.use_cases.controlPlan.GetControlPlansByYear +import org.junit.jupiter.api.Test +import org.mockito.BDDMockito +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.context.annotation.Import +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +@Import(WebSecurityConfig::class) +@WebMvcTest(value = [(ControlPlansController::class)]) +class ControlPlansControllerITests { + @Autowired private lateinit var mockMvc: MockMvc + + @MockBean private lateinit var getControlPlansByYear: GetControlPlansByYear + + @MockBean private lateinit var getControlPlans: GetControlPlans + + @Test + fun `Should get all control plan themes`() { + // Given + val controlPlanTheme1 = + ControlPlanThemeEntity( + id = 1, + theme = "Theme Police des mouillages", + ) + val controlPlanTheme2 = + ControlPlanThemeEntity( + id = 2, + theme = "Theme Protection des espèces", + ) + val controlPlanSubTheme1 = + ControlPlanSubThemeEntity( + id = 10, + themeId = 1, + subTheme = "SubTheme ZMEL", + year = 2024, + ) + val controlPlanTag = + ControlPlanTagEntity( + id = 100, + themeId = 2, + tag = "Tag Bichique", + ) + val controlPlan = + Triple( + listOf(controlPlanTheme1, controlPlanTheme2), + listOf(controlPlanSubTheme1), + listOf(controlPlanTag), + ) + BDDMockito.given(getControlPlans.execute()).willReturn(controlPlan) + // When + mockMvc.perform(get("/bff/v1/control_plans")) + // Then + .andExpect(status().isOk) + .andExpect(jsonPath("$.themes[\"1\"].id").value(controlPlanTheme1.id)) + .andExpect(jsonPath("$.themes[\"1\"].id").value(controlPlanTheme1.id)) + .andExpect(jsonPath("$.subThemes[\"10\"].id").value(controlPlanSubTheme1.id)) + .andExpect( + jsonPath("$.subThemes[\"10\"].subTheme") + .value(controlPlanSubTheme1.subTheme), + ) + .andExpect( + jsonPath("$.subThemes[\"10\"].themeId").value(controlPlanSubTheme1.themeId), + ) + .andExpect(jsonPath("$.tags[\"100\"].id").value(controlPlanTag.id)) + .andExpect(jsonPath("$.tags[\"100\"].tag").value(controlPlanTag.tag)) + .andExpect(jsonPath("$.tags[\"100\"].themeId").value(controlPlanTag.themeId)) + + verify(getControlPlans).execute() + } + + @Test + fun `Should get all control plan themes by year`() { + // Given + val controlPlanTheme1 = + ControlPlanThemeEntity( + id = 1, + theme = "Theme Police des mouillages", + ) + val controlPlanTheme2 = + ControlPlanThemeEntity( + id = 2, + theme = "Theme Protection des espèces", + ) + val controlPlanSubTheme1 = + ControlPlanSubThemeEntity( + id = 10, + themeId = 1, + subTheme = "SubTheme ZMEL", + year = 2024, + ) + val controlPlanTag = + ControlPlanTagEntity( + id = 100, + themeId = 2, + tag = "Tag Bichique", + ) + val controlPlan = + Triple( + listOf(controlPlanTheme1, controlPlanTheme2), + listOf(controlPlanSubTheme1), + listOf(controlPlanTag), + ) + BDDMockito.given(getControlPlansByYear.execute(2024)).willReturn(controlPlan) + // When + mockMvc.perform(get("/bff/v1/control_plans/2024")) + // Then + .andExpect(status().isOk) + .andExpect(jsonPath("$.themes[\"1\"].id").value(controlPlanTheme1.id)) + .andExpect(jsonPath("$.themes[\"1\"].id").value(controlPlanTheme1.id)) + .andExpect(jsonPath("$.subThemes[\"10\"].id").value(controlPlanSubTheme1.id)) + .andExpect( + jsonPath("$.subThemes[\"10\"].subTheme") + .value(controlPlanSubTheme1.subTheme), + ) + .andExpect( + jsonPath("$.subThemes[\"10\"].themeId").value(controlPlanSubTheme1.themeId), + ) + .andExpect(jsonPath("$.tags[\"100\"].id").value(controlPlanTag.id)) + .andExpect(jsonPath("$.tags[\"100\"].tag").value(controlPlanTag.tag)) + .andExpect(jsonPath("$.tags[\"100\"].themeId").value(controlPlanTag.themeId)) + + verify(getControlPlansByYear).execute(2024) + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/MissionsControllerITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/MissionsControllerITests.kt index 3c0725316f..350d93e7cc 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/MissionsControllerITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/MissionsControllerITests.kt @@ -10,6 +10,7 @@ import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ActionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ThemeEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.ActionTargetTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.EnvActionControlEntity @@ -20,10 +21,10 @@ import fr.gouv.cacem.monitorenv.domain.entities.reporting.SourceTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.reporting.TargetTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.semaphore.SemaphoreEntity import fr.gouv.cacem.monitorenv.domain.use_cases.missions.* +import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.EnvActionAttachedToReportingIds import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.MissionDTO import fr.gouv.cacem.monitorenv.domain.use_cases.reportings.dtos.ReportingDTO import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.inputs.missions.CreateOrUpdateMissionDataInput -import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.inputs.missions.EnvActionAttachedToReportingIds import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.inputs.missions.MissionEnvActionDataInput import org.hamcrest.Matchers.equalTo import org.junit.jupiter.api.Test @@ -66,12 +67,16 @@ class MissionsControllerITests { @Autowired private lateinit var objectMapper: ObjectMapper + private val polygon = + WKTReader() + .read( + "MULTIPOLYGON (((-4.54877817 48.30555988, -4.54997332 48.30597601, -4.54998501 48.30718823, -4.5487929 48.30677461, -4.54877817 48.30555988)))", + ) as + MultiPolygon + private val point = WKTReader().read("POINT (-4.54877816747593 48.305559876971)") as Point + @Test fun `Should create a new mission`() { - val wktReader = WKTReader() - val multipolygonString = - "MULTIPOLYGON (((-4.54877817 48.30555988, -4.54997332 48.30597601, -4.54998501 48.30718823, -4.5487929 48.30677461, -4.54877817 48.30555988)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon // Given val expectedNewMission = MissionDTO( @@ -129,18 +134,20 @@ class MissionsControllerITests { @Test fun `Should get all missions`() { // Given - val wktReader = WKTReader() - val multipolygonString = - "MULTIPOLYGON (((-4.54877817 48.30555988, -4.54997332 48.30597601, -4.54998501 48.30718823, -4.5487929 48.30677461, -4.54877817 48.30555988)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon - - val point = wktReader.read("POINT (-4.54877816747593 48.305559876971)") as Point val controlEnvAction = EnvActionControlEntity( id = UUID.fromString("d0f5f3a0-0b1a-4b0e-9b0a-0b0b0b0b0b0b"), actionStartDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), actionEndDateTimeUtc = ZonedDateTime.parse("2022-01-23T20:29:03Z"), + controlPlans = + listOf( + EnvActionControlPlanEntity( + subThemeIds = listOf(1), + tagIds = listOf(1, 2), + themeId = 1, + ), + ), geom = point, facade = "Outre-Mer", department = "29", @@ -194,7 +201,8 @@ class MissionsControllerITests { listOf( LegacyControlUnitResourceEntity( id = 2, - controlUnitId = 1, + controlUnitId = + 1, name = "Ressource 2", ), @@ -241,8 +249,8 @@ class MissionsControllerITests { reportType = ReportingTypeEnum .INFRACTION_SUSPICION, - theme = "Theme", - subThemes = listOf("SubTheme"), + themeId = 12, + subThemeIds = listOf(82), actionTaken = "ActionTaken", isControlRequired = true, hasNoUnitAvailable = true, @@ -289,6 +297,7 @@ class MissionsControllerITests { mockMvc.perform(get("/bff/v1/missions")) // Then .andExpect(status().isOk) + .andDo(MockMvcResultHandlers.print()) .andExpect(jsonPath("$.length()", equalTo(1))) .andExpect(jsonPath("$[0].id", equalTo(10))) .andExpect( @@ -334,6 +343,12 @@ class MissionsControllerITests { equalTo("2022-01-23T20:29:03Z"), ), ) + .andExpect(jsonPath("$[0].envActions[0].controlPlans[0].themeId", equalTo(1))) + .andExpect( + jsonPath("$[0].envActions[0].controlPlans[0].subThemeIds[0]", equalTo(1)), + ) + .andExpect(jsonPath("$[0].envActions[0].controlPlans[0].tagIds[0]", equalTo(1))) + .andExpect(jsonPath("$[0].envActions[0].controlPlans[0].tagIds[1]", equalTo(2))) .andExpect(jsonPath("$[0].envActions[0].geom.type", equalTo("Point"))) .andExpect(jsonPath("$[0].envActions[0].facade", equalTo("Outre-Mer"))) .andExpect(jsonPath("$[0].envActions[0].department", equalTo("29"))) @@ -454,17 +469,19 @@ class MissionsControllerITests { // Given val requestedId = 0 - val wktReader = WKTReader() - val multipolygonString = - "MULTIPOLYGON (((-4.54877817 48.30555988, -4.54997332 48.30597601, -4.54998501 48.30718823, -4.5487929 48.30677461, -4.54877817 48.30555988)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon - val point = wktReader.read("POINT (-4.54877816747593 48.305559876971)") as Point - val controlEnvAction = EnvActionControlEntity( id = UUID.fromString("d0f5f3a0-0b1a-4b0e-9b0a-0b0b0b0b0b0b"), actionStartDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), actionEndDateTimeUtc = ZonedDateTime.parse("2022-01-23T20:29:03Z"), + controlPlans = + listOf( + EnvActionControlPlanEntity( + subThemeIds = listOf(1), + tagIds = listOf(1, 2), + themeId = 1, + ), + ), geom = point, facade = "Outre-Mer", department = "29", @@ -518,8 +535,10 @@ class MissionsControllerITests { listOf( LegacyControlUnitResourceEntity( id = 2, - controlUnitId = 1, - name = "Ressource 2", + controlUnitId = + 1, + name = + "Ressource 2", ), ), isArchived = false, @@ -564,8 +583,8 @@ class MissionsControllerITests { reportType = ReportingTypeEnum .INFRACTION_SUSPICION, - theme = "Theme", - subThemes = listOf("SubTheme"), + themeId = 12, + subThemeIds = listOf(82), actionTaken = "ActionTaken", isControlRequired = true, hasNoUnitAvailable = true, @@ -601,6 +620,7 @@ class MissionsControllerITests { // When mockMvc.perform(get("/bff/v1/missions/$requestedId")) // Then + .andDo(MockMvcResultHandlers.print()) .andExpect(status().isOk) .andExpect(jsonPath("$.missionTypes[0]", equalTo(MissionTypeEnum.SEA.toString()))) .andExpect(jsonPath("$.id", equalTo(10))) @@ -644,6 +664,10 @@ class MissionsControllerITests { equalTo("2022-01-23T20:29:03Z"), ), ) + .andExpect(jsonPath("$.envActions[0].controlPlans[0].themeId", equalTo(1))) + .andExpect(jsonPath("$.envActions[0].controlPlans[0].subThemeIds[0]", equalTo(1))) + .andExpect(jsonPath("$.envActions[0].controlPlans[0].tagIds[0]", equalTo(1))) + .andExpect(jsonPath("$.envActions[0].controlPlans[0].tagIds[1]", equalTo(2))) .andExpect(jsonPath("$.envActions[0].geom.type", equalTo("Point"))) .andExpect(jsonPath("$.envActions[0].facade", equalTo("Outre-Mer"))) .andExpect(jsonPath("$.envActions[0].department", equalTo("29"))) @@ -838,20 +862,21 @@ class MissionsControllerITests { @Test fun `Should get all engaged control units`() { // Given - given(getEngagedControlUnits.execute()).willReturn( - listOf( - Pair( - LegacyControlUnitEntity( - id = 123, - administration = "Admin", - resources = listOf(), - isArchived = false, - name = "Control Unit Name", + given(getEngagedControlUnits.execute()) + .willReturn( + listOf( + Pair( + LegacyControlUnitEntity( + id = 123, + administration = "Admin", + resources = listOf(), + isArchived = false, + name = "Control Unit Name", + ), + listOf(MissionSourceEnum.MONITORFISH), ), - listOf(MissionSourceEnum.MONITORFISH), ), - ), - ) + ) // When mockMvc.perform(get("/bff/v1/missions/engaged_control_units")) diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsControllerITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsControllerITests.kt index 338bd5b428..f741ee1e8f 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsControllerITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/api/endpoints/bff/ReportingsControllerITests.kt @@ -82,8 +82,8 @@ class ReportingsControllerITests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(64, 82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -117,8 +117,8 @@ class ReportingsControllerITests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(64, 82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -155,9 +155,9 @@ class ReportingsControllerITests { .andExpect(jsonPath("$.seaFront").value("Facade 1")) .andExpect(jsonPath("$.description").value("description")) .andExpect(jsonPath("$.reportType").value("INFRACTION_SUSPICION")) - .andExpect(jsonPath("$.theme").value("theme")) - .andExpect(jsonPath("$.subThemes[0]").value("subTheme1")) - .andExpect(jsonPath("$.subThemes[1]").value("subTheme2")) + .andExpect(jsonPath("$.themeId").value(12)) + .andExpect(jsonPath("$.subThemeIds[0]").value(64)) + .andExpect(jsonPath("$.subThemeIds[1]").value(82)) .andExpect( jsonPath("$.actionTaken").value("actions effectuées blabla"), ) @@ -188,8 +188,8 @@ class ReportingsControllerITests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(64, 82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -234,9 +234,9 @@ class ReportingsControllerITests { .andExpect(jsonPath("$.seaFront").value("Facade 1")) .andExpect(jsonPath("$.description").value("description")) .andExpect(jsonPath("$.reportType").value("INFRACTION_SUSPICION")) - .andExpect(jsonPath("$.theme").value("theme")) - .andExpect(jsonPath("$.subThemes[0]").value("subTheme1")) - .andExpect(jsonPath("$.subThemes[1]").value("subTheme2")) + .andExpect(jsonPath("$.themeId").value(12)) + .andExpect(jsonPath("$.subThemeIds[0]").value(64)) + .andExpect(jsonPath("$.subThemeIds[1]").value(82)) .andExpect( jsonPath("$.actionTaken").value("actions effectuées blabla"), ) @@ -266,8 +266,8 @@ class ReportingsControllerITests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(64, 82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -324,8 +324,8 @@ class ReportingsControllerITests { seaFront = "Facade 1", description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = listOf("subTheme1", "subTheme2"), + themeId = 12, + subThemeIds = listOf(64, 82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -359,12 +359,8 @@ class ReportingsControllerITests { geom = polygon, description = "description", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "theme", - subThemes = - listOf( - "subTheme1", - "subTheme2", - ), + themeId = 12, + subThemeIds = listOf(64, 82), actionTaken = "actions effectuées blabla", isControlRequired = true, hasNoUnitAvailable = true, @@ -400,9 +396,9 @@ class ReportingsControllerITests { .andExpect(jsonPath("$.seaFront").value("Facade 1")) .andExpect(jsonPath("$.description").value("description")) .andExpect(jsonPath("$.reportType").value("INFRACTION_SUSPICION")) - .andExpect(jsonPath("$.theme").value("theme")) - .andExpect(jsonPath("$.subThemes[0]").value("subTheme1")) - .andExpect(jsonPath("$.subThemes[1]").value("subTheme2")) + .andExpect(jsonPath("$.themeId").value(12)) + .andExpect(jsonPath("$.subThemeIds[0]").value(64)) + .andExpect(jsonPath("$.subThemeIds[1]").value(82)) .andExpect( jsonPath("$.actionTaken").value("actions effectuées blabla"), ) diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanSubThemeRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanSubThemeRepositoryITests.kt new file mode 100644 index 0000000000..b355a573aa --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanSubThemeRepositoryITests.kt @@ -0,0 +1,44 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +class JpaControlPlanSubThemeRepositoryITests : AbstractDBTests() { + @Autowired + private lateinit var jpaControlPlanSubThemeRepository: JpaControlPlanSubThemeRepository + + @Test + fun `findAll Should return all control plan subthemes `() { + // When + val requestedControlPlanSubThemes = jpaControlPlanSubThemeRepository.findAll() + // Then + assertThat(requestedControlPlanSubThemes.size).isEqualTo(161) + assertThat(requestedControlPlanSubThemes[5].id).isEqualTo(6) + assertThat(requestedControlPlanSubThemes[5].themeId).isEqualTo(4) + assertThat(requestedControlPlanSubThemes[5].subTheme) + .isEqualTo( + "Atteinte aux biens culturels", + ) + + assertThat(requestedControlPlanSubThemes[5].year).isEqualTo(2023) + } + + @Test + fun `findByYear Should return all control plan theme for a specific year`() { + // When + val requestedControlPlanSubThemesFor2023 = jpaControlPlanSubThemeRepository.findByYear(2023) + val requestedControlPlanSubThemesFor2024 = jpaControlPlanSubThemeRepository.findByYear(2024) + // Then + assertThat(requestedControlPlanSubThemesFor2023.size).isEqualTo(83) + assertThat(requestedControlPlanSubThemesFor2024.size).isEqualTo(78) + assertThat(requestedControlPlanSubThemesFor2024[5].id).isEqualTo(105) + assertThat(requestedControlPlanSubThemesFor2024[5].themeId).isEqualTo(101) + assertThat(requestedControlPlanSubThemesFor2024[5].subTheme) + .isEqualTo( + "Usagers ZMEL", + ) + + assertThat(requestedControlPlanSubThemesFor2024[5].year).isEqualTo(2024) + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanTagRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanTagRepositoryITests.kt new file mode 100644 index 0000000000..6f96a6f954 --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanTagRepositoryITests.kt @@ -0,0 +1,39 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +class JpaControlPlanTagRepositoryITests : AbstractDBTests() { + @Autowired private lateinit var jpaControlPlanTagRepository: JpaControlPlanTagRepository + + @Test + fun `findAll Should return all control plan tags`() { + // When + val requestedControlPlanTags = jpaControlPlanTagRepository.findAll() + // Then + assertThat(requestedControlPlanTags.size).isEqualTo(17) + assertThat(requestedControlPlanTags[5].id).isEqualTo(6) + assertThat(requestedControlPlanTags[5].themeId).isEqualTo(11) + assertThat(requestedControlPlanTags[5].tag) + .isEqualTo( + "Mammifères marins", + ) + } + + @Test + fun `findByYear Should return all control plan tags for a specific year`() { + // When + val requestedControlPlanTagsFor2023 = jpaControlPlanTagRepository.findByYear(2023) + val requestedControlPlanTagsFor2024 = jpaControlPlanTagRepository.findByYear(2024) + // Then + assertThat(requestedControlPlanTagsFor2023.size).isEqualTo(68) + assertThat(requestedControlPlanTagsFor2024.size).isEqualTo(65) + assertThat(requestedControlPlanTagsFor2024[5].id).isEqualTo(10) + assertThat(requestedControlPlanTagsFor2024[5].themeId).isEqualTo(103) + assertThat(requestedControlPlanTagsFor2024[5].tag) + .isEqualTo( + "Mammifères marins", + ) + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanThemeRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanThemeRepositoryITests.kt new file mode 100644 index 0000000000..b93afd52cf --- /dev/null +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaControlPlanThemeRepositoryITests.kt @@ -0,0 +1,32 @@ +package fr.gouv.cacem.monitorenv.infrastructure.database.repositories + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +class JpaControlPlanThemeRepositoryITests : AbstractDBTests() { + @Autowired private lateinit var jpaControlPlanThemeRepository: JpaControlPlanThemeRepository + + @Test + fun `findAll Should return all control plan themes`() { + // When + val requestedControlPlanThemes = jpaControlPlanThemeRepository.findAll() + // Then + assertThat(requestedControlPlanThemes.size).isEqualTo(34) + assertThat(requestedControlPlanThemes[5].id).isEqualTo(6) + assertThat(requestedControlPlanThemes[5].theme).isEqualTo("Divers") + } + + @Test + fun `findByYear Should return all control plan theme for a specific year`() { + // When + val requestedControlPlanThemesFor2023 = jpaControlPlanThemeRepository.findByYear(2023) + val requestedControlPlanThemesFor2024 = jpaControlPlanThemeRepository.findByYear(2024) + // Then + assertThat(requestedControlPlanThemesFor2023.size).isEqualTo(83) + assertThat(requestedControlPlanThemesFor2024.size).isEqualTo(78) + assertThat(requestedControlPlanThemesFor2024[5].id).isEqualTo(3) + assertThat(requestedControlPlanThemesFor2024[5].theme) + .isEqualTo("Arrêté à visa environnemental") + } +} diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepositoryITests.kt index 8effac223e..8c9d912e5c 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepositoryITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaMissionRepositoryITests.kt @@ -6,9 +6,9 @@ import fr.gouv.cacem.monitorenv.domain.entities.controlUnit.LegacyControlUnitRes import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionSourceEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.MissionTypeEnum +import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionControlPlanEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionNoteEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.EnvActionSurveillanceEntity -import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.ThemeEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.ActionTargetTypeEnum import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.EnvActionControlEntity import fr.gouv.cacem.monitorenv.domain.entities.mission.envAction.envActionControl.infraction.* @@ -16,8 +16,8 @@ import fr.gouv.cacem.monitorenv.domain.use_cases.missions.dtos.MissionDTO import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable import org.junit.jupiter.api.Test -import org.locationtech.jts.geom.MultiPoint import org.locationtech.jts.geom.MultiPolygon +import org.locationtech.jts.geom.Point import org.locationtech.jts.io.WKTReader import org.springframework.beans.factory.annotation.Autowired import org.springframework.dao.DataIntegrityViolationException @@ -31,34 +31,21 @@ import java.util.* class JpaMissionRepositoryITests : AbstractDBTests() { @Autowired private lateinit var jpaMissionRepository: JpaMissionRepository - @Autowired private lateinit var jpaReportingRepository: JpaReportingRepository - @Autowired private lateinit var jpaControlUnitRepository: JpaControlUnitRepository @Autowired private lateinit var jpaControlUnitResourceRepository: JpaControlUnitResourceRepository - @Test - @Transactional - fun `findByControlUnitId should find the matching missions`() { - val foundMissions = jpaMissionRepository.findByControlUnitId(10002) - - assertThat(foundMissions).hasSize(17) - } + private val polygon = WKTReader().read( + "MULTIPOLYGON (((-4.54877817 48.30555988, -4.54997332 48.30597601, -4.54998501 48.30718823, -4.5487929 48.30677461, -4.54877817 48.30555988)))", + ) as MultiPolygon + private val point = WKTReader().read("POINT (-4.54877816747593 48.305559876971)") as Point @Test @Transactional - fun `findByControlUnitResourceId should find the matching missions`() { - val foundMissions = jpaMissionRepository.findByControlUnitResourceId(8) - - assertThat(foundMissions).hasSize(4) - } - - @Test - @Transactional - fun `save should create a new mission`() { + fun `delete Should set the deleted flag as true`() { // Given - val existingMissions = + val missionsList = jpaMissionRepository.findAllFullMissions( startedAfter = ZonedDateTime.parse("2022-01-01T10:54:00Z").toInstant(), startedBefore = ZonedDateTime.parse("2022-08-08T00:00:00Z").toInstant(), @@ -67,328 +54,22 @@ class JpaMissionRepositoryITests : AbstractDBTests() { seaFronts = null, pageable = Pageable.unpaged(), ) - - assertThat(existingMissions).hasSize(21) - - val wktReader = WKTReader() - - val multipolygonString = - "MULTIPOLYGON(((-2.7335 47.6078, -2.7335 47.8452, -3.6297 47.8452, -3.6297 47.6078, -2.7335 47.6078)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon - - val multipointString = "MULTIPOINT((49.354105 -0.427455))" - val point = wktReader.read(multipointString) as MultiPoint - - val noteObservations = "Quelqu'un aurait vu quelque chose quelque part à un certain moment." - - val newMission = - MissionEntity( - missionTypes = listOf(MissionTypeEnum.SEA), - startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), - isClosed = false, - isDeleted = false, - missionSource = MissionSourceEnum.MONITORENV, - hasMissionOrder = false, - isUnderJdp = false, - envActions = - listOf( - EnvActionControlEntity( - id = - UUID.fromString( - "33310163-4e22-4d3d-b585-dac4431eb4b5", - ), - facade = "Facade 1", - department = "Department 1", - geom = point, - vehicleType = VehicleTypeEnum.VEHICLE_LAND, - isAdministrativeControl = true, - isComplianceWithWaterRegulationsControl = true, - isSafetyEquipmentAndStandardsComplianceControl = - true, - isSeafarersControl = true, - ), - EnvActionSurveillanceEntity( - id = - UUID.fromString( - "a6c4bd17-eb45-4504-ab15-7a18ea714a10", - ), - facade = "Facade 2", - department = "Department 2", - geom = polygon, - ), - EnvActionNoteEntity( - id = - UUID.fromString( - "126ded89-2dc0-4c77-9bf2-49f86b9a71a1", - ), - observations = noteObservations, - ), - ), - controlUnits = - listOf( - LegacyControlUnitEntity( - id = 10121, - name = "PAM Jeanne Barret", - administration = "DIRM / DM", - isArchived = false, - resources = - listOf( - LegacyControlUnitResourceEntity( - id = 8, - controlUnitId = 10121, - name = "PAM Jeanne Barret", - ), - ), - ), - ), - isGeometryComputedFromControls = false, - ) + assertThat(missionsList).hasSize(21) // When - val newMissionCreated = jpaMissionRepository.save(newMission) + jpaMissionRepository.delete(3) // Then - assertThat(newMissionCreated.mission.controlUnits).hasSize(1) - assertThat(newMissionCreated.mission.controlUnits.first().id).isEqualTo(10121) - assertThat(newMissionCreated.mission.controlUnits.first().name) - .isEqualTo("PAM Jeanne Barret") - assertThat(newMissionCreated.mission.controlUnits.first().administration) - .isEqualTo("DIRM / DM") - assertThat(newMissionCreated.mission.controlUnits.first().resources).hasSize(1) - assertThat(newMissionCreated.mission.controlUnits.first().resources.first().id).isEqualTo(8) - assertThat(newMissionCreated.mission.controlUnits.first().resources.first().controlUnitId) - .isEqualTo(10121) - assertThat(newMissionCreated.mission.controlUnits.first().resources.first().name) - .isEqualTo("PAM Jeanne Barret") - assertThat(newMissionCreated.mission.envActions).hasSize(3) - assertThat(newMissionCreated.mission.envActions?.first()?.facade).isEqualTo("Facade 1") - assertThat(newMissionCreated.mission.envActions?.first()?.department) - .isEqualTo("Department 1") - assertThat(newMissionCreated.mission.envActions?.get(1)?.facade).isEqualTo("Facade 2") - assertThat(newMissionCreated.mission.envActions?.get(1)?.department) - .isEqualTo("Department 2") - assertThat( - (newMissionCreated.mission.envActions?.get(2) as EnvActionNoteEntity) - .observations, - ) - .isEqualTo( - noteObservations, - ) - - val missions = + val nextMissionList = jpaMissionRepository.findAllFullMissions( startedAfter = ZonedDateTime.parse("2022-01-01T10:54:00Z").toInstant(), startedBefore = ZonedDateTime.parse("2022-08-08T00:00:00Z").toInstant(), missionTypes = null, missionStatuses = null, seaFronts = null, - pageable = Pageable.unpaged(), - ) - - assertThat(missions).hasSize(22) - } - - @Test - @Transactional - fun `save should update mission resources`() { - // Given - val newMission = - MissionEntity( - missionTypes = listOf(MissionTypeEnum.SEA), - startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), - isClosed = false, - isDeleted = false, - missionSource = MissionSourceEnum.MONITORENV, - hasMissionOrder = false, - isUnderJdp = false, - controlUnits = - listOf( - LegacyControlUnitEntity( - id = 10004, - name = "DPM – DDTM 35", - administration = "DDTM", - isArchived = false, - resources = - listOf( - LegacyControlUnitResourceEntity( - id = 8, - controlUnitId = 10004, - name = "PAM Jeanne Barret", - ), - ), - ), - ), - isGeometryComputedFromControls = false, - ) - jpaMissionRepository.save(newMission) - - // When - val newMissionUpdated = - jpaMissionRepository.save( - newMission.copy( - controlUnits = - listOf( - LegacyControlUnitEntity( - id = 10002, - name = "DML 2A", - administration = "DIRM / DM", - isArchived = false, - resources = - listOf( - LegacyControlUnitResourceEntity( - id = 3, - controlUnitId = - 10002, - name = - "Semi-rigide 1", - ), - LegacyControlUnitResourceEntity( - id = 5, - controlUnitId = - 10002, - name = "Voiture", - ), - ), - ), - ), - ), - ) - - // Then - assertThat(newMissionUpdated.mission.controlUnits).hasSize(1) - assertThat(newMissionUpdated.mission.controlUnits.first().id).isEqualTo(10002) - assertThat(newMissionUpdated.mission.controlUnits.first().name).isEqualTo("DML 2A") - assertThat(newMissionUpdated.mission.controlUnits.first().administration) - .isEqualTo("DIRM / DM") - assertThat(newMissionUpdated.mission.controlUnits.first().resources).hasSize(2) - assertThat(newMissionUpdated.mission.controlUnits.first().resources.first().id).isEqualTo(3) - assertThat(newMissionUpdated.mission.controlUnits.first().resources.first().controlUnitId) - .isEqualTo(10002) - assertThat(newMissionUpdated.mission.controlUnits.first().resources.first().name) - .isEqualTo("Semi-rigide 1") - assertThat(newMissionUpdated.mission.controlUnits.first().resources.last().id).isEqualTo(5) - assertThat(newMissionUpdated.mission.controlUnits.first().resources.last().controlUnitId) - .isEqualTo(10002) - assertThat(newMissionUpdated.mission.controlUnits.first().resources.last().name) - .isEqualTo("Voiture") - } - - @Test - @Transactional - fun `save should update existing mission with existing resources`() { - // Given - val mission = jpaMissionRepository.findById(25) - val newControlUnitResource = jpaControlUnitResourceRepository.findById(10) - val newControlUnit = - jpaControlUnitRepository.findById( - requireNotNull(newControlUnitResource.controlUnit.id), - ) - - val nextMission = - mission.copy( - controlUnits = - mission.controlUnits.plus( - LegacyControlUnitEntity( - id = requireNotNull(newControlUnit.controlUnit.id), - administration = newControlUnit.administration.name, - isArchived = newControlUnit.controlUnit.isArchived, - name = newControlUnit.controlUnit.name, - resources = - listOf( - newControlUnitResource - .toLegacyControlUnitResource(), - ), - contact = null, - ), - ), - ) - - val updatedMission = jpaMissionRepository.save(nextMission) - - assertThat(updatedMission.mission.controlUnits).hasSize(2) - assertThat(updatedMission.mission.controlUnits.first().id).isEqualTo(10002) - assertThat(updatedMission.mission.controlUnits.first().resources).hasSize(1) - assertThat(updatedMission.mission.controlUnits.first().resources.first().id).isEqualTo(3) - assertThat(updatedMission.mission.controlUnits.first().resources.first().controlUnitId) - .isEqualTo(10002) - assertThat(updatedMission.mission.controlUnits.last().id).isEqualTo(10018) - assertThat(updatedMission.mission.controlUnits.last().resources).hasSize(1) - assertThat(updatedMission.mission.controlUnits.last().resources.first().id).isEqualTo(10) - assertThat(updatedMission.mission.controlUnits.last().resources.first().controlUnitId) - .isEqualTo(10018) - } - - @Test - @Transactional - fun `save should throw an exception When the resource id is not found`() { - // Given - val newMission = - MissionEntity( - missionTypes = listOf(MissionTypeEnum.SEA), - startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), - isClosed = false, - isDeleted = false, - missionSource = MissionSourceEnum.MONITORENV, - hasMissionOrder = false, - isUnderJdp = false, - controlUnits = - listOf( - LegacyControlUnitEntity( - id = 5, - name = "DPM – DDTM 35", - administration = "DDTM", - isArchived = false, - resources = - listOf( - LegacyControlUnitResourceEntity( - id = 123456, - controlUnitId = 5, - name = "PAM Jeanne Barret", - ), - ), - ), - ), - isGeometryComputedFromControls = false, - ) - - // When - val throwable = catchThrowable { jpaMissionRepository.save(newMission) } - - // Then - assertThat(throwable).isInstanceOf(InvalidDataAccessApiUsageException::class.java) - } - - @Test - @Transactional - fun `save should throw an exception When the unit id is not found`() { - // Given - val newMission = - MissionEntity( - missionTypes = listOf(MissionTypeEnum.SEA), - startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), - isClosed = false, - isDeleted = false, - missionSource = MissionSourceEnum.MONITORENV, - hasMissionOrder = false, - isUnderJdp = false, - controlUnits = - listOf( - LegacyControlUnitEntity( - id = 123456, - name = "PAM Jeanne Barret", - administration = "", - isArchived = false, - resources = listOf(), - ), - ), - isGeometryComputedFromControls = false, + pageable = Pageable.unpaged(), ) - - // When - val throwable = catchThrowable { jpaMissionRepository.save(newMission) } - - // Then - assertThat(throwable).isInstanceOf(DataIntegrityViolationException::class.java) + assertThat(nextMissionList).hasSize(20) } @Test @@ -596,51 +277,296 @@ class JpaMissionRepositoryITests : AbstractDBTests() { seaFronts = null, missionSources = listOf( - MissionSourceEnum.MONITORFISH, - MissionSourceEnum.POSEIDON_CACEM, - MissionSourceEnum.POSEIDON_CNSP, + MissionSourceEnum.MONITORFISH, + MissionSourceEnum.POSEIDON_CACEM, + MissionSourceEnum.POSEIDON_CNSP, + ), + pageable = Pageable.unpaged(), + ) + assertThat(missions).hasSize(3) + } + + @Test + @Transactional + fun `findByControlUnitId should find the matching missions`() { + val foundMissions = jpaMissionRepository.findByControlUnitId(10002) + + assertThat(foundMissions).hasSize(17) + } + + @Test + @Transactional + fun `findByControlUnitResourceId should find the matching missions`() { + val foundMissions = jpaMissionRepository.findByControlUnitResourceId(8) + + assertThat(foundMissions).hasSize(4) + } + + @Test + @Transactional + fun `findById Should return specified mission`() { + // When + val firstMission = + MissionDTO( + mission = + MissionEntity( + id = 10, + missionTypes = listOf(MissionTypeEnum.LAND), + openBy = "KIM", + closedBy = "TRA", + facade = "NAMO", + observationsCacem = + "Remain vote several ok. Bring American play woman challenge. Throw low law positive seven.", + startDateTimeUtc = + ZonedDateTime.parse("2022-03-21T12:11:13Z"), + endDateTimeUtc = null, + geom = polygon, + isClosed = false, + isDeleted = false, + envActions = listOf(), + missionSource = MissionSourceEnum.MONITORENV, + hasMissionOrder = false, + isUnderJdp = false, + controlUnits = + listOf( + LegacyControlUnitEntity( + id = 10002, + administration = "DDTM", + isArchived = false, + name = "DML 2A", + resources = + listOf( + LegacyControlUnitResourceEntity( + id = 3, + controlUnitId = + 10002, + name = + "Semi-rigide 1", + ), + LegacyControlUnitResourceEntity( + id = 4, + controlUnitId = + 10002, + name = + "Semi-rigide 2", + ), + LegacyControlUnitResourceEntity( + id = 5, + controlUnitId = + 10002, + name = + "Voiture", + ), + ), + ), + ), + isGeometryComputedFromControls = false, + ), + ) + val mission = jpaMissionRepository.findFullMissionById(10) + + assertThat(mission).isEqualTo(firstMission) + } + + @Test + @Transactional + fun `findById Should return specified mission and associated env actions and associated envActionReportingIds`() { + // When + val missionDTO = jpaMissionRepository.findFullMissionById(34) + assertThat(missionDTO.mission.id).isEqualTo(34) + assertThat(missionDTO.mission.envActions).hasSize(2) + assertThat( + missionDTO.envActionsAttachedToReportingIds?.get(0)?.first, + ) + .isEqualTo(UUID.fromString("b8007c8a-5135-4bc3-816f-c69c7b75d807")) + assertThat(missionDTO.envActionsAttachedToReportingIds?.get(0)?.second).isEqualTo(listOf(6)) + } + + @Test + @Transactional + fun `findByIds() should find the matching missions`() { + val foundMissions = jpaMissionRepository.findByIds(listOf(50, 51, 52)) + + assertThat(foundMissions).hasSize(3) + } + + @Test + @Transactional + fun `save should create a new mission`() { + // Given + val existingMissions = + jpaMissionRepository.findAllFullMissions( + startedAfter = ZonedDateTime.parse("2022-01-01T10:54:00Z").toInstant(), + startedBefore = ZonedDateTime.parse("2022-08-08T00:00:00Z").toInstant(), + missionTypes = null, + missionStatuses = null, + seaFronts = null, + pageable = Pageable.unpaged(), + ) + + assertThat(existingMissions).hasSize(21) + + val noteObservations = "Quelqu'un aurait vu quelque chose quelque part à un certain moment." + + val newMission = + MissionEntity( + missionTypes = listOf(MissionTypeEnum.SEA), + startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), + isClosed = false, + isDeleted = false, + missionSource = MissionSourceEnum.MONITORENV, + hasMissionOrder = false, + isUnderJdp = false, + envActions = + listOf( + EnvActionControlEntity( + id = + UUID.fromString( + "33310163-4e22-4d3d-b585-dac4431eb4b5", + ), + facade = "Facade 1", + controlPlans = listOf( + EnvActionControlPlanEntity( + subThemeIds = listOf(1), + tagIds = listOf(1, 2), + themeId = 1, + ), + ), + department = "Department 1", + geom = point, + vehicleType = VehicleTypeEnum.VEHICLE_LAND, + isAdministrativeControl = true, + isComplianceWithWaterRegulationsControl = true, + isSafetyEquipmentAndStandardsComplianceControl = + true, + isSeafarersControl = true, + ), + EnvActionSurveillanceEntity( + id = + UUID.fromString( + "a6c4bd17-eb45-4504-ab15-7a18ea714a10", + ), + facade = "Facade 2", + department = "Department 2", + geom = polygon, + ), + EnvActionNoteEntity( + id = + UUID.fromString( + "126ded89-2dc0-4c77-9bf2-49f86b9a71a1", + ), + observations = noteObservations, + ), + ), + controlUnits = + listOf( + LegacyControlUnitEntity( + id = 10121, + name = "PAM Jeanne Barret", + administration = "DIRM / DM", + isArchived = false, + resources = + listOf( + LegacyControlUnitResourceEntity( + id = 8, + controlUnitId = 10121, + name = "PAM Jeanne Barret", + ), + ), + ), + ), + isGeometryComputedFromControls = false, + ) + + // When + val newMissionCreated = jpaMissionRepository.save(newMission) + + // Then + assertThat(newMissionCreated.mission.controlUnits).hasSize(1) + assertThat(newMissionCreated.mission.controlUnits.first().id).isEqualTo(10121) + assertThat(newMissionCreated.mission.controlUnits.first().name) + .isEqualTo("PAM Jeanne Barret") + assertThat(newMissionCreated.mission.controlUnits.first().administration) + .isEqualTo("DIRM / DM") + assertThat(newMissionCreated.mission.controlUnits.first().resources).hasSize(1) + assertThat(newMissionCreated.mission.controlUnits.first().resources.first().id).isEqualTo(8) + assertThat(newMissionCreated.mission.controlUnits.first().resources.first().controlUnitId) + .isEqualTo(10121) + assertThat(newMissionCreated.mission.controlUnits.first().resources.first().name) + .isEqualTo("PAM Jeanne Barret") + assertThat(newMissionCreated.mission.envActions).hasSize(3) + assertThat(newMissionCreated.mission.envActions?.first()?.facade).isEqualTo("Facade 1") + assertThat(newMissionCreated.mission.envActions?.first()?.department) + .isEqualTo("Department 1") + assertThat(newMissionCreated.mission.envActions?.get(1)?.facade).isEqualTo("Facade 2") + assertThat(newMissionCreated.mission.envActions?.get(1)?.department) + .isEqualTo("Department 2") + assertThat( + (newMissionCreated.mission.envActions?.get(2) as EnvActionNoteEntity) + .observations, + ) + .isEqualTo( + noteObservations, + ) + + val missions = + jpaMissionRepository.findAllFullMissions( + startedAfter = ZonedDateTime.parse("2022-01-01T10:54:00Z").toInstant(), + startedBefore = ZonedDateTime.parse("2022-08-08T00:00:00Z").toInstant(), + missionTypes = null, + missionStatuses = null, + seaFronts = null, + pageable = Pageable.unpaged(), + ) + + assertThat(missions).hasSize(22) + } + + @Test + @Transactional + fun `save should update mission resources`() { + // Given + val newMission = + MissionEntity( + missionTypes = listOf(MissionTypeEnum.SEA), + startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), + isClosed = false, + isDeleted = false, + missionSource = MissionSourceEnum.MONITORENV, + hasMissionOrder = false, + isUnderJdp = false, + controlUnits = + listOf( + LegacyControlUnitEntity( + id = 10004, + name = "DPM – DDTM 35", + administration = "DDTM", + isArchived = false, + resources = + listOf( + LegacyControlUnitResourceEntity( + id = 8, + controlUnitId = 10004, + name = "PAM Jeanne Barret", + ), + ), + ), ), - pageable = Pageable.unpaged(), + isGeometryComputedFromControls = false, ) - assertThat(missions).hasSize(3) - } + jpaMissionRepository.save(newMission) - @Test - @Transactional - fun `findById Should return specified mission`() { // When - val wktReader = WKTReader() - val multipolygonString = - "MULTIPOLYGON (((-4.99360539 48.42853215, -4.99359905 48.42848997, -4.99359291 48.42844777, -4.99358697 48.42840556, -4.99358123 48.42836334, -4.99357569 48.4283211, -4.99357035 48.42827886, -4.9935652 48.4282366, -4.99356026 48.42819434, -4.99355552 48.42815206, -4.99355097 48.42810977, -4.99354663 48.42806748, -4.99354249 48.42802517, -4.99353854 48.42798286, -4.9935348 48.42794054, -4.99353125 48.42789821, -4.99352791 48.42785587, -4.99352476 48.42781353, -4.99352182 48.42777118, -4.99351907 48.42772882, -4.99351653 48.42768646, -4.99351418 48.4276441, -4.99351203 48.42760173, -4.99351009 48.42755935, -4.99350834 48.42751697, -4.9935068 48.42747459, -4.99350545 48.42743221, -4.99350431 48.42738982, -4.99350336 48.42734743, -4.99350262 48.42730504, -4.99350207 48.42726264, -4.99350173 48.42722025, -4.99350158 48.42717785, -4.99350164 48.42713546, -4.99350189 48.42709307, -4.99350235 48.42705067, -4.99350301 48.42700828, -4.99350386 48.42696589, -4.99350492 48.4269235, -4.99350617 48.42688111, -4.99350763 48.42683873, -4.99350929 48.42679635, -4.99351114 48.42675397, -4.9935132 48.4267116, -4.99351545 48.42666923, -4.99351791 48.42662687, -4.99352057 48.42658451, -4.99352342 48.42654216, -4.99352648 48.42649981, -4.99352973 48.42645747, -4.99353319 48.42641514, -4.99353685 48.42637282, -4.9935407 48.4263305, -4.99354476 48.42628819, -4.99354901 48.42624589, -4.99355346 48.4262036, -4.99355812 48.42616132, -4.99356297 48.42611905, -4.99356802 48.42607679, -4.99357328 48.42603454, -4.99357873 48.4259923, -4.99358438 48.42595007, -4.99359023 48.42590785, -4.99359628 48.42586565, -4.99360253 48.42582346, -4.99360898 48.42578128, -4.99361562 48.42573912, -4.99362247 48.42569697, -4.99362951 48.42565484, -4.99363676 48.42561272, -4.9936442 48.42557061, -4.99365184 48.42552853, -4.99365968 48.42548645, -4.99366772 48.4254444, -4.99367596 48.42540236, -4.99368439 48.42536034, -4.99369302 48.42531833, -4.99370186 48.42527635, -4.99371089 48.42523438, -4.99372011 48.42519243, -4.99372954 48.42515051, -4.99373916 48.4251086, -4.99374898 48.42506671, -4.993759 48.42502484, -4.99376922 48.424983, -4.99377963 48.42494117, -4.99379024 48.42489937, -4.99380105 48.42485759, -4.99381206 48.42481583, -4.99382326 48.4247741, -4.99383466 48.42473239, -4.99384626 48.4246907, -4.99385805 48.42464904, -4.99387004 48.42460741, -4.99388223 48.42456579, -4.99389461 48.42452421, -4.99390719 48.42448265, -4.99391996 48.42444111, -4.99393293 48.42439961, -4.9939461 48.42435813, -4.99395946 48.42431668, -4.99397302 48.42427525, -4.99398677 48.42423386, -4.99400072 48.42419249, -4.99401487 48.42415116, -4.9940292 48.42410985, -4.99404374 48.42406857, -4.99405847 48.42402733, -4.99407339 48.42398611, -4.99408851 48.42394493, -4.99410382 48.42390378, -4.99411932 48.42386266, -4.99413502 48.42382157, -4.99415092 48.42378052, -4.994167 48.4237395, -4.99418328 48.42369851, -4.99419976 48.42365756, -4.99421643 48.42361664, -4.99423329 48.42357576, -4.99425034 48.42353491, -4.99426759 48.4234941, -4.99428502 48.42345333, -4.99430265 48.42341259, -4.99432048 48.42337189, -4.99433849 48.42333122, -4.9943567 48.4232906, -4.9943751 48.42325001, -4.99439369 48.42320946, -4.99441247 48.42316895, -4.99443144 48.42312848, -4.9944506 48.42308805, -4.99446996 48.42304766, -4.9944895 48.42300731, -4.99450924 48.422967, -4.99452916 48.42292673, -4.99454928 48.42288651, -4.99456958 48.42284633, -4.99459007 48.42280619, -4.99461076 48.42276609, -4.99463163 48.42272603, -4.99465269 48.42268602, -4.99467394 48.42264606, -4.99469538 48.42260614, -4.99471701 48.42256626, -4.99473882 48.42252643, -4.99476082 48.42248665, -4.99478301 48.42244691, -4.99480539 48.42240721, -4.99482796 48.42236757, -4.99485071 48.42232797, -4.99487365 48.42228842, -4.99489677 48.42224892, -4.99492008 48.42220947, -4.99494358 48.42217006, -4.99496727 48.42213071, -4.99499113 48.4220914, -4.99501519 48.42205215, -4.99503943 48.42201294, -4.99506385 48.42197379, -4.99508846 48.42193469, -4.99511326 48.42189563, -4.99513823 48.42185664, -4.99516339 48.42181769, -4.99518874 48.4217788, -4.99521427 48.42173995, -4.99523998 48.42170117, -4.99526587 48.42166243, -4.99529195 48.42162376, -4.99531821 48.42158513, -4.99534465 48.42154656, -4.99537128 48.42150805, -4.99539808 48.42146959, -4.99542507 48.42143119, -4.99545224 48.42139285, -4.99547959 48.42135456, -4.99550711 48.42131633, -4.99553482 48.42127816, -4.99556271 48.42124004, -4.99559078 48.42120199, -4.99561903 48.42116399, -4.99564746 48.42112605, -4.99567606 48.42108817, -4.99570485 48.42105035, -4.99573381 48.4210126, -4.99576295 48.4209749, -4.99579227 48.42093726, -4.99582177 48.42089969, -4.99585144 48.42086218, -4.99588129 48.42082473, -4.99591132 48.42078734, -4.99594152 48.42075001, -4.9959719 48.42071275, -4.99600246 48.42067555, -4.99603319 48.42063842, -4.9960641 48.42060135, -4.99609518 48.42056435, -4.99612643 48.42052741, -4.99615786 48.42049053, -4.99618946 48.42045372, -4.99622124 48.42041698, -4.99625319 48.42038031, -4.99628531 48.4203437, -4.9963176 48.42030716, -4.99635007 48.42027069, -4.99638271 48.42023428, -4.99641552 48.42019794, -4.9964485 48.42016168, -4.99648166 48.42012548, -4.99651498 48.42008935, -4.99654847 48.42005329, -4.99658214 48.4200173, -4.99661597 48.41998138, -4.99664997 48.41994553, -4.99668415 48.41990976, -4.99671849 48.41987405, -4.996753 48.41983842, -4.99678767 48.41980286, -4.99682252 48.41976737, -4.99685753 48.41973196, -4.99689271 48.41969662, -4.99692805 48.41966135, -4.99696356 48.41962616, -4.99699924 48.41959104, -4.99703508 48.41955599, -4.99707109 48.41952102, -4.99710726 48.41948613, -4.9971436 48.41945131, -4.9971801 48.41941657, -4.99721677 48.4193819, -4.9972536 48.41934732, -4.99729059 48.4193128, -4.99732774 48.41927837, -4.99736506 48.41924402, -4.99740254 48.41920974, -4.99744018 48.41917554, -4.99747798 48.41914142, -4.99751594 48.41910738, -4.99755406 48.41907342, -4.99759234 48.41903953, -4.99763079 48.41900573, -4.99766939 48.41897201, -4.99770815 48.41893837, -4.99774707 48.41890481, -4.99778614 48.41887133, -4.99782538 48.41883794, -4.99786477 48.41880463, -4.99790432 48.4187714, -4.99794402 48.41873825, -4.99798388 48.41870518, -4.9980239 48.4186722, -4.99806408 48.4186393, -4.9981044 48.41860649, -4.99814489 48.41857376, -4.99818552 48.41854112, -4.99822631 48.41850856, -4.99826726 48.41847609, -4.99830835 48.4184437, -4.9983496 48.4184114, -4.99839101 48.41837918, -4.99843256 48.41834705, -4.99847426 48.41831501, -4.99851612 48.41828306, -4.99855813 48.41825119, -4.99860028 48.41821941, -4.99864259 48.41818772, -4.99868504 48.41815612, -4.99872765 48.41812461, -4.9987704 48.41809319, -4.9988133 48.41806185, -4.99885635 48.41803061, -4.99889955 48.41799946, -4.99894289 48.41796839, -4.99898638 48.41793742, -4.99903001 48.41790654, -4.99907379 48.41787575, -4.99911772 48.41784505, -4.99916179 48.41781444, -4.999206 48.41778393, -4.99925036 48.41775351, -4.99929486 48.41772318, -4.99933951 48.41769294, -4.99938429 48.4176628, -4.99942922 48.41763276, -4.99947429 48.4176028, -4.9995195 48.41757294, -4.99956485 48.41754318, -4.99961035 48.41751351, -4.99965598 48.41748393, -4.99970175 48.41745445, -4.99974766 48.41742507, -4.99979371 48.41739578, -4.99983989 48.41736659, -4.99988622 48.4173375, -4.99993268 48.4173085, -4.99997927 48.4172796, -5.00002601 48.4172508, -5.00007288 48.4172221, -5.00011988 48.41719349, -5.00016702 48.41716498, -5.00021429 48.41713657, -5.0002617 48.41710826, -5.00030924 48.41708005, -5.00035691 48.41705194, -5.00040472 48.41702393, -5.00045266 48.41699602, -5.00050072 48.41696821, -5.00054892 48.4169405, -5.00059725 48.41691289, -5.00064571 48.41688538, -5.0006943 48.41685797, -5.00074302 48.41683067, -5.00079187 48.41680346, -5.00084085 48.41677636, -5.00088995 48.41674937, -5.00093918 48.41672247, -5.00098854 48.41669568, -5.00103802 48.41666899, -5.00108763 48.4166424, -5.00113736 48.41661592, -5.00118722 48.41658954, -5.0012372 48.41656327, -5.00128731 48.4165371, -5.00133754 48.41651104, -5.00138789 48.41648508, -5.00143837 48.41645923, -5.00148896 48.41643348, -5.00153968 48.41640784, -5.00159052 48.4163823, -5.00164148 48.41635688, -5.00169256 48.41633155, -5.00174375 48.41630634, -5.00179507 48.41628123, -5.0018465 48.41625623, -5.00189805 48.41623134, -5.00194972 48.41620655, -5.00200151 48.41618187, -5.00205341 48.41615731, -5.00210543 48.41613285, -5.00215756 48.4161085, -5.00220981 48.41608425, -5.00226217 48.41606012, -5.00231465 48.4160361, -5.00236723 48.41601219, -5.00241993 48.41598838, -5.00247275 48.41596469, -5.00252567 48.41594111, -5.00257871 48.41591764, -5.00263185 48.41589428, -5.00268511 48.41587103, -5.00273847 48.41584789, -5.00279195 48.41582486, -5.00284553 48.41580195, -5.00289922 48.41577915, -5.00295301 48.41575646, -5.00300692 48.41573388, -5.00306093 48.41571142, -5.00311504 48.41568907, -5.00316927 48.41566683, -5.00322359 48.4156447, -5.00327802 48.41562269, -5.00333255 48.4156008, -5.00338719 48.41557901, -5.00344193 48.41555735, -5.00349677 48.41553579, -5.00355171 48.41551435, -5.00360676 48.41549303, -5.0036619 48.41547182, -5.00371714 48.41545073, -5.00377249 48.41542975, -5.00382793 48.41540889, -5.00388347 48.41538814, -5.0039391 48.41536751, -5.00399484 48.415347, -5.00405067 48.4153266, -5.00410659 48.41530632, -5.00416261 48.41528616, -5.00421873 48.41526611, -5.00427494 48.41524619, -5.00433125 48.41522638, -5.00438764 48.41520668, -5.00444413 48.41518711, -5.00450072 48.41516765, -5.00455739 48.41514831, -5.00461416 48.41512909, -5.00467101 48.41510999, -5.00472796 48.41509101, -5.00478499 48.41507215, -5.00484211 48.41505341, -5.00489932 48.41503478, -5.00495662 48.41501628, -5.00501401 48.4149979, -5.00507148 48.41497963, -5.00512904 48.41496149, -5.00518668 48.41494347, -5.00524441 48.41492556, -5.00530222 48.41490778, -5.00536012 48.41489012, -5.0054181 48.41487258, -5.00547616 48.41485516, -5.0055343 48.41483786, -5.00559252 48.41482069, -5.00565083 48.41480364, -5.00570921 48.4147867, -5.00576768 48.4147699, -5.00582622 48.41475321, -5.00588485 48.41473664, -5.00594355 48.4147202, -5.00600232 48.41470388, -5.00606118 48.41468769, -5.00612011 48.41467161, -5.00617911 48.41465566, -5.00623819 48.41463984, -5.00629735 48.41462414, -5.00635658 48.41460856, -5.00641588 48.4145931, -5.00647525 48.41457777, -5.0065347 48.41456257, -5.00659422 48.41454748, -5.00665381 48.41453253, -5.00671347 48.41451769, -5.0067732 48.41450298, -5.00683299 48.4144884, -5.00689286 48.41447394, -5.00695279 48.41445961, -5.0070128 48.4144454, -5.00707286 48.41443132, -5.007133 48.41441736, -5.0071932 48.41440353, -5.00725346 48.41438983, -5.00731379 48.41437625, -5.00737419 48.4143628, -5.00743464 48.41434947, -5.00749516 48.41433627, -5.00755574 48.4143232, -5.00761638 48.41431025, -5.00767709 48.41429743, -5.00773785 48.41428474, -5.00779867 48.41427218, -5.00785955 48.41425974, -5.00792049 48.41424743, -5.00798149 48.41423525, -5.00804255 48.41422319, -5.00810366 48.41421126, -5.00816482 48.41419946, -5.00822605 48.41418779, -5.00828732 48.41417625, -5.00834866 48.41416483, -5.00841004 48.41415354, -5.00847148 48.41414238, -5.00853297 48.41413135, -5.00859451 48.41412045, -5.0086561 48.41410968, -5.00871775 48.41409903, -5.00877944 48.41408852, -5.00884119 48.41407813, -5.00890298 48.41406787, -5.00896482 48.41405775, -5.0090267 48.41404775, -5.00908864 48.41403788, -5.00915062 48.41402814, -5.00921264 48.41401853, -5.00927471 48.41400905, -5.00933683 48.4139997, -5.00939899 48.41399048, -5.00946119 48.41398139, -5.00952344 48.41397243, -5.00958572 48.4139636, -5.00964805 48.4139549, -5.00971042 48.41394633, -5.00977283 48.41393789, -5.00983528 48.41392958, -5.00989777 48.4139214, -5.00996029 48.41391335, -5.01002285 48.41390544, -5.01008545 48.41389765, -5.01014809 48.41389, -5.01021076 48.41388247, -5.01027347 48.41387508, -5.01033621 48.41386782, -5.01039899 48.41386069, -5.0104618 48.41385369, -5.01052464 48.41384682, -5.01058752 48.41384009, -5.01065042 48.41383348, -5.01071336 48.41382701, -5.01077633 48.41382067, -5.01083932 48.41381446, -5.01090235 48.41380838, -5.0109654 48.41380243, -5.01102848 48.41379662, -5.01109159 48.41379094, -5.01115473 48.41378539, -5.01121789 48.41377997, -5.01128107 48.41377468, -5.01134429 48.41376953, -5.01140752 48.41376451, -5.01147078 48.41375962, -5.01153406 48.41375486, -5.01159736 48.41375023, -5.01166069 48.41374574, -5.01172403 48.41374138, -5.0117874 48.41373715, -5.01185078 48.41373306, -5.01191419 48.41372909, -5.01197761 48.41372526, -5.01204105 48.41372157, -5.01210451 48.413718, -5.01216798 48.41371457, -5.01223147 48.41371127, -5.01229498 48.4137081, -5.0123585 48.41370507, -5.01242203 48.41370217, -5.01248558 48.4136994, -5.01254914 48.41369676, -5.01261271 48.41369426, -5.0126763 48.41369189, -5.01273989 48.41368965, -5.0128035 48.41368755, -5.01286711 48.41368558, -5.01293073 48.41368374, -5.01299437 48.41368204, -5.013058 48.41368047, -5.01312165 48.41367903, -5.0131853 48.41367772, -5.01324896 48.41367655, -5.01331263 48.41367551, -5.0133763 48.41367461, -5.01343997 48.41367383, -5.01350364 48.41367319, -5.01356732 48.41367269, -5.013631 48.41367231, -5.01369469 48.41367207, -5.01375837 48.41367197, -5.01382205 48.41367199, -5.01388573 48.41367215, -5.01394942 48.41367244, -5.0140131 48.41367287, -5.01407677 48.41367343, -5.01414045 48.41367412, -5.01420412 48.41367494, -5.01426779 48.4136759, -5.01433145 48.41367699, -5.01439511 48.41367822, -5.01445876 48.41367957, -5.0145224 48.41368106, -5.01458604 48.41368269, -5.01464966 48.41368444, -5.01471328 48.41368633, -5.0147769 48.41368836, -5.0148405 48.41369051, -5.01490409 48.4136928, -5.01496767 48.41369522, -5.01503123 48.41369778, -5.01509479 48.41370046, -5.01515833 48.41370328, -5.01522186 48.41370624, -5.01528537 48.41370932, -5.01534887 48.41371254, -5.01541236 48.41371589, -5.01547582 48.41371938, -5.01553928 48.41372299, -5.01560271 48.41372674, -5.01566613 48.41373062, -5.01572952 48.41373464, -5.0157929 48.41373879, -5.01585626 48.41374307, -5.0159196 48.41374748, -5.01598291 48.41375202, -5.01604621 48.4137567, -5.01610948 48.41376151, -5.01617273 48.41376645, -5.01623595 48.41377152, -5.01629915 48.41377673, -5.01636233 48.41378207, -5.01642548 48.41378754, -5.01648861 48.41379314, -5.01655171 48.41379887, -5.01661478 48.41380474, -5.01667782 48.41381074, -5.01674083 48.41381687, -5.01680382 48.41382313, -5.01686677 48.41382952, -5.0169297 48.41383605, -5.01699259 48.4138427, -5.01705545 48.41384949, -5.01711828 48.41385641, -5.01718108 48.41386346, -5.01724384 48.41387064, -5.01730657 48.41387795, -5.01736927 48.4138854, -5.01743192 48.41389297, -5.01749455 48.41390068, -5.01755713 48.41390851, -5.01761968 48.41391648, -5.01768219 48.41392458, -5.01774467 48.41393281, -5.0178071 48.41394117, -5.01786949 48.41394966, -5.01793185 48.41395828, -5.01799416 48.41396703, -5.01805643 48.41397591, -5.01811866 48.41398492, -5.01818084 48.41399406, -5.01824298 48.41400333, -5.01830508 48.41401274, -5.01836714 48.41402227, -5.01842914 48.41403193, -5.01849111 48.41404172, -5.01855302 48.41405164, -5.01861489 48.41406169, -5.01867671 48.41407186, -5.01873848 48.41408217, -5.01880021 48.41409261, -5.01886188 48.41410317, -5.01892351 48.41411387, -5.01898508 48.41412469, -5.0190466 48.41413565, -5.01910807 48.41414673, -5.01916949 48.41415794, -5.01923085 48.41416927, -5.01929216 48.41418074, -5.01935342 48.41419233, -5.01941462 48.41420405, -5.01947577 48.4142159, -5.01953686 48.41422788, -5.01959789 48.41423999, -5.01965886 48.41425222, -5.01971978 48.41426458, -5.01978064 48.41427707, -5.01984144 48.41428968, -5.01990218 48.41430242, -5.01996286 48.41431529, -5.02002348 48.41432829, -5.02008403 48.41434141, -5.02014453 48.41435466, -5.02020496 48.41436804, -5.02026533 48.41438154, -5.02032563 48.41439517, -5.02038587 48.41440892, -5.02044604 48.4144228, -5.02050615 48.4144368, -5.0205662 48.41445093, -5.02062617 48.41446519, -5.02068608 48.41447957, -5.02074592 48.41449408, -5.02080569 48.41450871, -5.02086539 48.41452347, -5.02092502 48.41453835, -5.02098458 48.41455336, -5.02104407 48.41456849, -5.02110349 48.41458374, -5.02116284 48.41459912, -5.02122211 48.41461463, -5.02128131 48.41463025, -5.02134044 48.414646, -5.02139949 48.41466188, -5.02145847 48.41467788, -5.02151737 48.414694, -5.02157619 48.41471024, -5.02163494 48.41472661, -5.02169361 48.4147431, -5.0217522 48.41475971, -5.02181071 48.41477644, -5.02186915 48.4147933, -5.0219275 48.41481028, -5.02198577 48.41482738, -5.02204397 48.4148446, -5.02210208 48.41486195, -5.02216011 48.41487941, -5.02221805 48.414897, -5.02227592 48.41491471, -5.0223337 48.41493254, -5.02239139 48.41495049, -5.022449 48.41496856, -5.02250653 48.41498675, -5.02256396 48.41500506, -5.02262132 48.41502349, -5.02267858 48.41504204, -5.02273576 48.41506071, -5.02279285 48.4150795, -5.02284984 48.41509841, -5.02290675 48.41511744, -5.02296357 48.41513659, -5.0230203 48.41515585, -5.02307694 48.41517524, -5.02313349 48.41519474, -5.02318994 48.41521436, -5.0232463 48.4152341, -5.02330257 48.41525395, -5.02335875 48.41527393, -5.02341483 48.41529402, -5.02347081 48.41531423, -5.0235267 48.41533455, -5.02358249 48.41535499, -5.02363819 48.41537555, -5.02369379 48.41539623, -5.02374929 48.41541702, -5.02380469 48.41543793, -5.02385999 48.41545895, -5.0239152 48.41548009, -5.0239703 48.41550134, -5.02402531 48.41552271, -5.02408021 48.41554419, -5.02413501 48.41556579, -5.02418971 48.41558751, -5.02424431 48.41560933, -5.0242988 48.41563127, -5.02435319 48.41565333, -5.02440747 48.4156755, -5.02446165 48.41569778, -5.02451573 48.41572017, -5.0245697 48.41574268, -5.02462356 48.4157653, -5.02467731 48.41578804, -5.02473096 48.41581088, -5.0247845 48.41583384, -5.02483793 48.41585691, -5.02489126 48.41588009, -5.02494447 48.41590338, -5.02499757 48.41592679, -5.02505056 48.4159503, -5.02510344 48.41597393, -5.02515621 48.41599766, -5.02520887 48.41602151, -5.02526141 48.41604547, -5.02531384 48.41606953, -5.02536616 48.41609371, -5.02541836 48.41611799, -5.02547045 48.41614238, -5.02552242 48.41616689, -5.02557428 48.4161915, -5.02562602 48.41621622, -5.02567764 48.41624104, -5.02572915 48.41626598, -5.02578054 48.41629102, -5.02583181 48.41631617, -5.02588296 48.41634143, -5.02593399 48.41636679, -5.0259849 48.41639226, -5.02603569 48.41641784, -5.02608636 48.41644352, -5.02613691 48.41646931, -5.02618734 48.4164952, -5.02623764 48.4165212, -5.02628782 48.41654731, -5.02633788 48.41657352, -5.02638782 48.41659983, -5.02643763 48.41662625, -5.02648731 48.41665277, -5.02653687 48.4166794, -5.02658631 48.41670613, -5.02663561 48.41673296, -5.02668479 48.41675989, -5.02673385 48.41678693, -5.02678277 48.41681407, -5.02683157 48.41684132, -5.02688024 48.41686866, -5.02692878 48.41689611, -5.02697719 48.41692366, -5.02702547 48.4169513, -5.02707362 48.41697905, -5.02712163 48.4170069, -5.02716952 48.41703485, -5.02721727 48.4170629, -5.02726489 48.41709105, -5.02731238 48.4171193, -5.02735974 48.41714765, -5.02740696 48.4171761, -5.02745404 48.41720465, -5.027501 48.41723329, -5.02754781 48.41726203, -5.02759449 48.41729087, -5.02764104 48.41731981, -5.02768744 48.41734885, -5.02773371 48.41737798, -5.02777985 48.41740721, -5.02782584 48.41743653, -5.02787169 48.41746595, -5.02791741 48.41749547, -5.02796299 48.41752508, -5.02800843 48.41755479, -5.02805372 48.41758459, -5.02809888 48.41761449, -5.02814389 48.41764448, -5.02818877 48.41767456, -5.0282335 48.41770474, -5.02827809 48.41773501, -5.02832253 48.41776538, -5.02836683 48.41779583, -5.02841099 48.41782638, -5.028455 48.41785703, -5.02849887 48.41788776, -5.0285426 48.41791859, -5.02858617 48.4179495, -5.02862961 48.41798051, -5.02867289 48.41801161, -5.02871603 48.4180428, -5.02875902 48.41807408, -5.02880186 48.41810545, -5.02884456 48.4181369, -5.02888711 48.41816845, -5.0289295 48.41820009, -5.02897175 48.41823181, -5.02901385 48.41826362, -5.0290558 48.41829552, -5.02909759 48.41832751, -5.02913924 48.41835959, -5.02918073 48.41839175, -5.02922208 48.418424, -5.02926327 48.41845633, -5.0293043 48.41848876, -5.02934519 48.41852126, -5.02938592 48.41855385, -5.02942649 48.41858653, -5.02946692 48.41861929, -5.02950718 48.41865214, -5.0295473 48.41868507, -5.02958725 48.41871808, -5.02962705 48.41875118, -5.0296667 48.41878436, -5.02970619 48.41881762, -5.02974552 48.41885097, -5.02978469 48.4188844, -5.0298237 48.41891791, -5.02986256 48.4189515, -5.02990126 48.41898517, -5.0299398 48.41901892, -5.02997818 48.41905275, -5.0300164 48.41908667, -5.03005446 48.41912066, -5.03009236 48.41915473, -5.0301301 48.41918888, -5.03016767 48.41922311, -5.03020509 48.41925742, -5.03024234 48.41929181, -5.03027943 48.41932627, -5.03031636 48.41936081, -5.03035312 48.41939543, -5.03038972 48.41943013, -5.03042616 48.4194649, -5.03046243 48.41949974, -5.03049854 48.41953467, -5.03053449 48.41956967, -5.03057026 48.41960474, -5.03060588 48.41963989, -5.03064132 48.41967511, -5.0306766 48.41971041, -5.03071172 48.41974578, -5.03074666 48.41978122, -5.03078144 48.41981674, -5.03081605 48.41985233, -5.0308505 48.41988799, -5.03088477 48.41992372, -5.03091888 48.41995952, -5.03095281 48.4199954, -5.03098658 48.42003134, -5.03102018 48.42006736, -5.03105361 48.42010345, -5.03108686 48.4201396, -5.03111995 48.42017583, -5.03115287 48.42021212, -5.03118561 48.42024849, -5.03121818 48.42028492, -5.03125058 48.42032142, -5.03128281 48.42035799, -5.03131486 48.42039462, -5.03134675 48.42043132, -5.03137845 48.42046809, -5.03140999 48.42050492, -5.03144135 48.42054182, -5.03147254 48.42057879, -5.03150355 48.42061582, -5.03153439 48.42065291, -5.03156505 48.42069007, -5.03159553 48.42072729, -5.03162584 48.42076458, -5.03165598 48.42080193, -5.03168594 48.42083934, -5.03171572 48.42087682, -5.03174532 48.42091435, -5.03177475 48.42095195, -5.031804 48.42098961, -5.03183307 48.42102733, -5.03186197 48.42106511, -5.03189068 48.42110295, -5.03191922 48.42114086, -5.03194758 48.42117882, -5.03197575 48.42121684, -5.03200375 48.42125492, -5.03203157 48.42129305, -5.03205921 48.42133125, -5.03208667 48.4213695, -5.03211395 48.42140781, -5.03214105 48.42144618, -5.03216796 48.4214846, -5.0321947 48.42152308, -5.03222125 48.42156162, -5.03224762 48.42160021, -5.03227381 48.42163885, -5.03229981 48.42167755, -5.03232564 48.42171631, -5.03235128 48.42175511, -5.03237673 48.42179398, -5.03240201 48.42183289, -5.0324271 48.42187186, -5.032452 48.42191088, -5.03247672 48.42194995, -5.03250126 48.42198907, -5.03252561 48.42202824, -5.03254978 48.42206747, -5.03257376 48.42210674, -5.03259756 48.42214607, -5.03262117 48.42218544, -5.0326446 48.42222487, -5.03266783 48.42226434, -5.03269089 48.42230386, -5.03271375 48.42234343, -5.03273643 48.42238304, -5.03275892 48.42242271, -5.03278123 48.42246242, -5.03280334 48.42250217, -5.03282527 48.42254198, -5.03284702 48.42258183, -5.03286857 48.42262172, -5.03288993 48.42266166, -5.03291111 48.42270164, -5.0329321 48.42274167, -5.0329529 48.42278174, -5.03297351 48.42282185, -5.03299393 48.42286201, -5.03301416 48.42290221, -5.0330342 48.42294245, -5.03305405 48.42298274, -5.03307371 48.42302306, -5.03309318 48.42306343, -5.03311246 48.42310383, -5.03313155 48.42314428, -5.03315044 48.42318476, -5.03316915 48.42322529, -5.03318766 48.42326585, -5.03320599 48.42330646, -5.03322412 48.4233471, -5.03324206 48.42338777, -5.03325981 48.42342849, -5.03327736 48.42346924, -5.03329473 48.42351003, -5.0333119 48.42355086, -5.03332888 48.42359172, -5.03334566 48.42363261, -5.03336225 48.42367355, -5.03337865 48.42371451, -5.03339486 48.42375551, -5.03341087 48.42379654, -5.03342669 48.42383761, -5.03344231 48.42387871, -5.03345774 48.42391984, -5.03347298 48.42396101, -5.03348802 48.4240022, -5.03350286 48.42404343, -5.03351752 48.42408469, -5.03353197 48.42412598, -5.03354624 48.42416729, -5.0335603 48.42420864, -5.03357418 48.42425002, -5.03358785 48.42429142, -5.03360133 48.42433286, -5.03361462 48.42437432, -5.03362771 48.42441581, -5.0336406 48.42445733, -5.0336533 48.42449887, -5.0336658 48.42454044, -5.03367811 48.42458204, -5.03369022 48.42462366, -5.03370213 48.42466531, -5.03371385 48.42470698, -5.03372537 48.42474867, -5.03373669 48.42479039, -5.03374782 48.42483214, -5.03375875 48.4248739, -5.03376948 48.42491569, -5.03378001 48.4249575, -5.03379035 48.42499933, -5.03380049 48.42504119, -5.03381043 48.42508306, -5.03382017 48.42512496, -5.03382972 48.42516687, -5.03383907 48.42520881, -5.03384822 48.42525077, -5.03385717 48.42529274, -5.03386593 48.42533473, -5.03387448 48.42537674, -5.03388284 48.42541877, -5.033891 48.42546082, -5.03389896 48.42550288, -5.03390672 48.42554496, -5.03391428 48.42558705, -5.03392165 48.42562916, -5.03392882 48.42567129, -5.03393578 48.42571343, -5.03394255 48.42575558, -5.03394912 48.42579775, -5.03395549 48.42583993, -5.03396166 48.42588213, -5.03396763 48.42592434, -5.03397341 48.42596656, -5.03397898 48.42600879, -5.03398435 48.42605103, -5.03398953 48.42609329, -5.0339945 48.42613555, -5.03399928 48.42617783, -5.03400385 48.42622011, -5.03400823 48.42626241, -5.03401241 48.42630471, -5.03401638 48.42634702, -5.03402016 48.42638934, -5.03402374 48.42643167, -5.03402712 48.42647401, -5.03403029 48.42651635, -5.03403327 48.4265587, -5.03403605 48.42660105, -5.03403863 48.42664341, -5.03404101 48.42668577, -5.03404318 48.42672814, -5.03404516 48.42677052, -5.03404694 48.4268129, -5.03404852 48.42685528, -5.0340499 48.42689766, -5.03405107 48.42694005, -5.03405205 48.42698244, -5.03405283 48.42702483, -5.03405341 48.42706722, -5.03405379 48.42710962, -5.03405396 48.42715201, -5.03405394 48.42719441, -5.03405372 48.4272368, -5.03405329 48.4272792, -5.03405267 48.42732159, -5.03405185 48.42736398, -5.03405082 48.42740637, -5.0340496 48.42744876, -5.03404818 48.42749114, -5.03404655 48.42753352, -5.03404473 48.4275759, -5.03404271 48.42761827, -5.03404048 48.42766064, -5.03403806 48.427703, -5.03403544 48.42774536, -5.03403261 48.42778772, -5.03402959 48.42783006, -5.03402637 48.4278724, -5.03402294 48.42791474, -5.03401932 48.42795706, -5.0340155 48.42799938, -5.03401148 48.42804169, -5.03400725 48.42808399, -5.03400283 48.42812628, -5.03399821 48.42816857, -5.03399339 48.42821084, -5.03398837 48.4282531, -5.03398315 48.42829535, -5.03397773 48.4283376, -5.03397211 48.42837982, -5.03396629 48.42842204, -5.03396027 48.42846425, -5.03395406 48.42850644, -5.03394764 48.42854862, -5.03394103 48.42859078, -5.03393421 48.42863294, -5.0339272 48.42867507, -5.03391999 48.42871719, -5.03391258 48.4287593, -5.03390497 48.42880139, -5.03389716 48.42884347, -5.03388915 48.42888552, -5.03388095 48.42892757, -5.03387254 48.42896959, -5.03386394 48.4290116, -5.03385514 48.42905358, -5.03384614 48.42909555, -5.03383695 48.4291375, -5.03382755 48.42917944, -5.03381796 48.42922135, -5.03380817 48.42926324, -5.03379818 48.42930511, -5.033788 48.42934696, -5.03377761 48.42938878, -5.03376703 48.42943059, -5.03375626 48.42947237, -5.03374528 48.42951413, -5.03373411 48.42955587, -5.03372274 48.42959759, -5.03371117 48.42963928, -5.03369941 48.42968094, -5.03368745 48.42972258, -5.0336753 48.4297642, -5.03366294 48.42980579, -5.0336504 48.42984735, -5.03363765 48.42988889, -5.03362471 48.4299304, -5.03361157 48.42997188, -5.03359824 48.43001334, -5.03358471 48.43005477, -5.03357099 48.43009617, -5.03355707 48.43013754, -5.03354296 48.43017888, -5.03352865 48.43022019, -5.03351414 48.43026147, -5.03349944 48.43030272, -5.03348455 48.43034394, -5.03346946 48.43038513, -5.03345418 48.43042628, -5.0334387 48.43046741, -5.03342303 48.4305085, -5.03340717 48.43054956, -5.03339111 48.43059058, -5.03337486 48.43063158, -5.03335841 48.43067253, -5.03334177 48.43071346, -5.03332494 48.43075434, -5.03330791 48.4307952, -5.0332907 48.43083601, -5.03327329 48.43087679, -5.03325568 48.43091754, -5.03323789 48.43095824, -5.0332199 48.43099891, -5.03320172 48.43103954, -5.03318335 48.43108014, -5.03316479 48.43112069, -5.03314603 48.43116121, -5.03312709 48.43120169, -5.03310795 48.43124212, -5.03308862 48.43128252, -5.03306911 48.43132287, -5.0330494 48.43136319, -5.0330295 48.43140346, -5.03300941 48.43144369, -5.03298913 48.43148388, -5.03296866 48.43152403, -5.03294801 48.43156413, -5.03292716 48.43160419, -5.03290612 48.43164421, -5.0328849 48.43168418, -5.03286349 48.43172411, -5.03284189 48.43176399, -5.0328201 48.43180383, -5.03279812 48.43184362, -5.03277595 48.43188337, -5.0327536 48.43192307, -5.03273106 48.43196272, -5.03270833 48.43200232, -5.03268542 48.43204188, -5.03266232 48.43208139, -5.03263903 48.43212085, -5.03261555 48.43216026, -5.03259189 48.43219962, -5.03256805 48.43223894, -5.03254402 48.4322782, -5.0325198 48.43231741, -5.0324954 48.43235657, -5.03247081 48.43239568, -5.03244604 48.43243474, -5.03242109 48.43247375, -5.03239595 48.4325127, -5.03237063 48.4325516, -5.03234512 48.43259045, -5.03231943 48.43262925, -5.03229356 48.43266799, -5.0322675 48.43270667, -5.03224126 48.4327453, -5.03221484 48.43278388, -5.03218824 48.4328224, -5.03216146 48.43286087, -5.03213449 48.43289928, -5.03210735 48.43293763, -5.03208002 48.43297593, -5.03205251 48.43301416, -5.03202482 48.43305235, -5.03199695 48.43309047, -5.0319689 48.43312853, -5.03194067 48.43316654, -5.03191227 48.43320448, -5.03188368 48.43324237, -5.03185491 48.4332802, -5.03182597 48.43331796, -5.03179685 48.43335567, -5.03176755 48.43339331, -5.03173807 48.4334309, -5.03170841 48.43346842, -5.03167858 48.43350588, -5.03164857 48.43354327, -5.03161839 48.43358061, -5.03158802 48.43361788, -5.03155749 48.43365508, -5.03152677 48.43369223, -5.03149589 48.4337293, -5.03146482 48.43376632, -5.03143358 48.43380327, -5.03140217 48.43384015, -5.03137059 48.43387697, -5.03133883 48.43391372, -5.03130689 48.4339504, -5.03127479 48.43398702, -5.03124251 48.43402357, -5.03121006 48.43406005, -5.03117743 48.43409646, -5.03114464 48.43413281, -5.03111167 48.43416909, -5.03107853 48.4342053, -5.03104522 48.43424143, -5.03101175 48.4342775, -5.0309781 48.4343135, -5.03094428 48.43434943, -5.03091029 48.43438529, -5.03087613 48.43442107, -5.0308418 48.43445679, -5.03080731 48.43449243, -5.03077264 48.434528, -5.03073781 48.43456349, -5.03070281 48.43459892, -5.03066765 48.43463427, -5.03063232 48.43466955, -5.03059682 48.43470475, -5.03056115 48.43473988, -5.03052532 48.43477493, -5.03048933 48.43480991, -5.03045316 48.43484482, -5.03041684 48.43487964, -5.03038035 48.4349144, -5.03034369 48.43494907, -5.03030688 48.43498367, -5.0302699 48.43501819, -5.03023275 48.43505263, -5.03019545 48.435087, -5.03015798 48.43512129, -5.03012035 48.4351555, -5.03008256 48.43518963, -5.0300446 48.43522368, -5.03000649 48.43525765, -5.02996822 48.43529154, -5.02992979 48.43532535, -5.02989119 48.43535908, -5.02985244 48.43539273, -5.02981353 48.4354263, -5.02977446 48.43545979, -5.02973524 48.4354932, -5.02969585 48.43552652, -5.02965631 48.43555976, -5.02961661 48.43559292, -5.02957676 48.43562599, -5.02953675 48.43565898, -5.02949658 48.43569189, -5.02945626 48.43572472, -5.02941578 48.43575745, -5.02937515 48.43579011, -5.02933437 48.43582268, -5.02929343 48.43585516, -5.02925234 48.43588756, -5.02921109 48.43591987, -5.0291697 48.4359521, -5.02912815 48.43598423, -5.02908645 48.43601629, -5.0290446 48.43604825, -5.02900259 48.43608013, -5.02896044 48.43611192, -5.02891814 48.43614362, -5.02887569 48.43617523, -5.02883309 48.43620675, -5.02879034 48.43623818, -5.02874744 48.43626953, -5.02870439 48.43630078, -5.0286612 48.43633195, -5.02861786 48.43636302, -5.02857437 48.436394, -5.02853074 48.4364249, -5.02848696 48.4364557, -5.02844304 48.4364864, -5.02839897 48.43651702, -5.02835476 48.43654755, -5.0283104 48.43657798, -5.0282659 48.43660832, -5.02822126 48.43663856, -5.02817647 48.43666871, -5.02813154 48.43669877, -5.02808647 48.43672874, -5.02804126 48.43675861, -5.02799591 48.43678838, -5.02795041 48.43681806, -5.02790478 48.43684765, -5.02785901 48.43687714, -5.0278131 48.43690653, -5.02776705 48.43693583, -5.02772086 48.43696503, -5.02767454 48.43699413, -5.02762807 48.43702314, -5.02758147 48.43705205, -5.02753474 48.43708086, -5.02748787 48.43710958, -5.02744086 48.4371382, -5.02739372 48.43716671, -5.02734644 48.43719513, -5.02729903 48.43722345, -5.02725149 48.43725167, -5.02720381 48.4372798, -5.027156 48.43730782, -5.02710806 48.43733574, -5.02705998 48.43736356, -5.02701178 48.43739128, -5.02696344 48.4374189, -5.02691498 48.43744642, -5.02686638 48.43747384, -5.02681766 48.43750115, -5.02676881 48.43752836, -5.02671983 48.43755548, -5.02667072 48.43758248, -5.02662148 48.43760939, -5.02657212 48.43763619, -5.02652263 48.43766289, -5.02647301 48.43768949, -5.02642327 48.43771598, -5.0263734 48.43774237, -5.02632341 48.43776865, -5.0262733 48.43779483, -5.02622306 48.4378209, -5.0261727 48.43784687, -5.02612222 48.43787273, -5.02607161 48.43789849, -5.02602089 48.43792414, -5.02597004 48.43794969, -5.02591907 48.43797513, -5.02586798 48.43800046, -5.02581678 48.43802568, -5.02576545 48.4380508, -5.02571401 48.43807581, -5.02566245 48.43810072, -5.02561077 48.43812551, -5.02555897 48.4381502, -5.02550706 48.43817478, -5.02545503 48.43819924, -5.02540289 48.43822361, -5.02535063 48.43824786, -5.02529825 48.438272, -5.02524577 48.43829603, -5.02519317 48.43831995, -5.02514045 48.43834377, -5.02508763 48.43836747, -5.02503469 48.43839106, -5.02498165 48.43841454, -5.02492849 48.43843791, -5.02487522 48.43846117, -5.02482184 48.43848432, -5.02476835 48.43850735, -5.02471476 48.43853028, -5.02466105 48.43855309, -5.02460724 48.43857579, -5.02455332 48.43859837, -5.0244993 48.43862085, -5.02444517 48.43864321, -5.02439093 48.43866546, -5.02433659 48.43868759, -5.02428215 48.43870961, -5.0242276 48.43873151, -5.02417295 48.43875331, -5.02411819 48.43877498, -5.02406334 48.43879655, -5.02400838 48.43881799, -5.02395332 48.43883933, -5.02389816 48.43886055, -5.0238429 48.43888165, -5.02378754 48.43890263, -5.02373208 48.43892351, -5.02367653 48.43894426, -5.02362087 48.4389649, -5.02356512 48.43898542, -5.02350927 48.43900583, -5.02345333 48.43902611, -5.02339729 48.43904629, -5.02334115 48.43906634, -5.02328493 48.43908628, -5.0232286 48.4391061, -5.02317219 48.4391258, -5.02311568 48.43914538, -5.02305908 48.43916485, -5.02300238 48.43918419, -5.0229456 48.43920342, -5.02288872 48.43922253, -5.02283176 48.43924152, -5.02277471 48.43926039, -5.02271756 48.43927914, -5.02266033 48.43929777, -5.02260301 48.43931628, -5.02254561 48.43933468, -5.02248811 48.43935295, -5.02243054 48.4393711, -5.02237287 48.43938913, -5.02231512 48.43940704, -5.02225729 48.43942483, -5.02219937 48.4394425, -5.02214137 48.43946005, -5.02208329 48.43947747, -5.02202512 48.43949478, -5.02196688 48.43951196, -5.02190855 48.43952902, -5.02185014 48.43954596, -5.02179166 48.43956278, -5.02173309 48.43957947, -5.02167444 48.43959605, -5.02161572 48.4396125, -5.02155692 48.43962882, -5.02149804 48.43964502, -5.02143909 48.43966111, -5.02138006 48.43967706, -5.02132096 48.4396929, -5.02126178 48.4397086, -5.02120253 48.43972419, -5.0211432 48.43973965, -5.0210838 48.43975499, -5.02102433 48.4397702, -5.02096479 48.43978529, -5.02090517 48.43980026, -5.02084549 48.4398151, -5.02078574 48.43982981, -5.02072591 48.4398444, -5.02066602 48.43985887, -5.02060606 48.43987321, -5.02054604 48.43988742, -5.02048594 48.43990151, -5.02042578 48.43991547, -5.02036556 48.43992931, -5.02030527 48.43994302, -5.02024491 48.43995661, -5.02018449 48.43997006, -5.02012401 48.4399834, -5.02006346 48.4399966, -5.02000286 48.44000968, -5.01994219 48.44002263, -5.01988146 48.44003546, -5.01982067 48.44004816, -5.01975982 48.44006073, -5.01969891 48.44007317, -5.01963794 48.44008549, -5.01957692 48.44009768, -5.01951584 48.44010974, -5.0194547 48.44012167, -5.0193935 48.44013348, -5.01933225 48.44014515, -5.01927095 48.4401567, -5.01920959 48.44016812, -5.01914817 48.44017942, -5.01908671 48.44019058, -5.01902519 48.44020162, -5.01896362 48.44021253, -5.018902 48.4402233, -5.01884032 48.44023395, -5.0187786 48.44024447, -5.01871683 48.44025486, -5.01865501 48.44026513, -5.01859314 48.44027526, -5.01853122 48.44028526, -5.01846926 48.44029514, -5.01840725 48.44030488, -5.0183452 48.4403145, -5.0182831 48.44032398, -5.01822095 48.44033334, -5.01815876 48.44034256, -5.01809653 48.44035166, -5.01803426 48.44036062, -5.01797194 48.44036945, -5.01790958 48.44037816, -5.01784718 48.44038673, -5.01778474 48.44039518, -5.01772226 48.44040349, -5.01765975 48.44041167, -5.01759719 48.44041972, -5.0175346 48.44042764, -5.01747197 48.44043543, -5.0174093 48.44044309, -5.0173466 48.44045062, -5.01728386 48.44045801, -5.01722108 48.44046528, -5.01715828 48.44047241, -5.01709544 48.44047941, -5.01703256 48.44048629, -5.01696966 48.44049302, -5.01690672 48.44049963, -5.01684375 48.44050611, -5.01678075 48.44051245, -5.01671773 48.44051867, -5.01665467 48.44052475, -5.01659158 48.4405307, -5.01652847 48.44053651, -5.01646533 48.4405422, -5.01640216 48.44054775, -5.01633897 48.44055317, -5.01627575 48.44055846, -5.01621251 48.44056362, -5.01614924 48.44056864, -5.01608595 48.44057354, -5.01602264 48.4405783, -5.01595931 48.44058292, -5.01589595 48.44058742, -5.01583257 48.44059178, -5.01576917 48.44059601, -5.01570576 48.44060011, -5.01564232 48.44060407, -5.01557886 48.4406079, -5.01551539 48.4406116, -5.0154519 48.44061517, -5.0153884 48.4406186, -5.01532487 48.44062191, -5.01526134 48.44062507, -5.01519778 48.44062811, -5.01513422 48.44063101, -5.01507064 48.44063378, -5.01500704 48.44063642, -5.01494344 48.44063892, -5.01487982 48.44064129, -5.0148162 48.44064353, -5.01475256 48.44064564, -5.01468891 48.44064761, -5.01462526 48.44064945, -5.01456159 48.44065115, -5.01449792 48.44065272, -5.01443424 48.44065416, -5.01437056 48.44065547, -5.01430686 48.44065664, -5.01424317 48.44065768, -5.01417947 48.44065859, -5.01411576 48.44065936, -5.01405205 48.44066, -5.01398834 48.44066051, -5.01392463 48.44066088, -5.01386091 48.44066112, -5.0137972 48.44066123, -5.01373348 48.4406612, -5.01366977 48.44066104, -5.01360605 48.44066075, -5.01354234 48.44066033, -5.01347863 48.44065977, -5.01341492 48.44065907, -5.01335122 48.44065825, -5.01328752 48.44065729, -5.01322382 48.4406562, -5.01316013 48.44065497, -5.01309645 48.44065362, -5.01303277 48.44065212, -5.0129691 48.4406505, -5.01290544 48.44064874, -5.01284179 48.44064685, -5.01277815 48.44064483, -5.01271451 48.44064267, -5.01265089 48.44064038, -5.01258728 48.44063796, -5.01252368 48.4406354, -5.01246009 48.44063272, -5.01239652 48.44062989, -5.01233296 48.44062694, -5.01226941 48.44062385, -5.01220588 48.44062063, -5.01214236 48.44061728, -5.01207886 48.44061379, -5.01201538 48.44061018, -5.01195191 48.44060642, -5.01188846 48.44060254, -5.01182504 48.44059852, -5.01176163 48.44059437, -5.01169824 48.44059009, -5.01163487 48.44058568, -5.01157152 48.44058113, -5.01150819 48.44057645, -5.01144489 48.44057164, -5.01138161 48.4405667, -5.01131835 48.44056162, -5.01125512 48.44055641, -5.01119191 48.44055107, -5.01112872 48.4405456, -5.01106557 48.44053999, -5.01100244 48.44053426, -5.01093934 48.44052839, -5.01087626 48.44052239, -5.01081322 48.44051626, -5.0107502 48.44050999, -5.01068721 48.4405036, -5.01062426 48.44049707, -5.01056133 48.44049041, -5.01049844 48.44048362, -5.01043558 48.4404767, -5.01037275 48.44046964, -5.01030996 48.44046246, -5.0102472 48.44045514, -5.01018447 48.44044769, -5.01012178 48.44044011, -5.01005913 48.44043241, -5.00999651 48.44042456, -5.00993394 48.44041659, -5.00987139 48.44040849, -5.00980889 48.44040026, -5.00974643 48.44039189, -5.00968401 48.4403834, -5.00962162 48.44037478, -5.00955928 48.44036602, -5.00949698 48.44035714, -5.00943472 48.44034812, -5.00937251 48.44033897, -5.00931033 48.4403297, -5.00924821 48.44032029, -5.00918612 48.44031076, -5.00912409 48.44030109, -5.00906209 48.4402913, -5.00900015 48.44028137, -5.00893825 48.44027132, -5.0088764 48.44026114, -5.0088146 48.44025082, -5.00875285 48.44024038, -5.00869115 48.44022981, -5.00862949 48.44021911, -5.00856789 48.44020828, -5.00850634 48.44019732, -5.00844484 48.44018624, -5.0083834 48.44017502, -5.008322 48.44016368, -5.00826067 48.44015221, -5.00819938 48.44014061, -5.00813815 48.44012888, -5.00807698 48.44011703, -5.00801586 48.44010504, -5.0079548 48.44009293, -5.0078938 48.44008069, -5.00783286 48.44006833, -5.00777197 48.44005583, -5.00771114 48.44004321, -5.00765038 48.44003047, -5.00758967 48.44001759, -5.00752903 48.44000459, -5.00746844 48.43999146, -5.00740792 48.43997821, -5.00734747 48.43996482, -5.00728707 48.43995132, -5.00722674 48.43993768, -5.00716648 48.43992392, -5.00710628 48.43991004, -5.00704614 48.43989602, -5.00698607 48.43988189, -5.00692607 48.43986762, -5.00686614 48.43985323, -5.00680628 48.43983872, -5.00674648 48.43982408, -5.00668675 48.43980932, -5.0066271 48.43979443, -5.00656751 48.43977942, -5.006508 48.43976428, -5.00644855 48.43974902, -5.00638918 48.43973363, -5.00632989 48.43971812, -5.00627066 48.43970249, -5.00621151 48.43968673, -5.00615244 48.43967085, -5.00609344 48.43965484, -5.00603451 48.43963871, -5.00597567 48.43962246, -5.0059169 48.43960609, -5.0058582 48.43958959, -5.00579959 48.43957297, -5.00574105 48.43955623, -5.0056826 48.43953936, -5.00562422 48.43952238, -5.00556593 48.43950527, -5.00550771 48.43948804, -5.00544958 48.43947068, -5.00539153 48.43945321, -5.00533356 48.43943562, -5.00527568 48.4394179, -5.00521787 48.43940006, -5.00516016 48.43938211, -5.00510253 48.43936403, -5.00504498 48.43934583, -5.00498752 48.43932751, -5.00493015 48.43930907, -5.00487287 48.43929051, -5.00481567 48.43927183, -5.00475856 48.43925304, -5.00470154 48.43923412, -5.00464461 48.43921508, -5.00458777 48.43919593, -5.00453103 48.43917665, -5.00447437 48.43915726, -5.0044178 48.43913775, -5.00436133 48.43911812, -5.00430495 48.43909837, -5.00424866 48.43907851, -5.00419247 48.43905852, -5.00413637 48.43903842, -5.00408037 48.43901821, -5.00402447 48.43899787, -5.00396866 48.43897742, -5.00391294 48.43895685, -5.00385733 48.43893617, -5.00380181 48.43891537, -5.00374639 48.43889445, -5.00369107 48.43887342, -5.00363585 48.43885227, -5.00358073 48.43883101, -5.00352571 48.43880963, -5.00347079 48.43878814, -5.00341597 48.43876653, -5.00336126 48.43874481, -5.00330665 48.43872297, -5.00325214 48.43870102, -5.00319773 48.43867896, -5.00314343 48.43865678, -5.00308924 48.43863449, -5.00303515 48.43861209, -5.00298117 48.43858957, -5.00292729 48.43856694, -5.00287352 48.4385442, -5.00281986 48.43852134, -5.00276631 48.43849837, -5.00271286 48.43847529, -5.00265953 48.4384521, -5.0026063 48.4384288, -5.00255318 48.43840539, -5.00250018 48.43838186, -5.00244729 48.43835823, -5.00239451 48.43833448, -5.00234184 48.43831063, -5.00228928 48.43828666, -5.00223684 48.43826259, -5.00218451 48.4382384, -5.0021323 48.43821411, -5.0020802 48.4381897, -5.00202822 48.43816519, -5.00197635 48.43814057, -5.0019246 48.43811584, -5.00187296 48.438091, -5.00182145 48.43806606, -5.00177005 48.43804101, -5.00171877 48.43801585, -5.00166761 48.43799058, -5.00161657 48.43796521, -5.00156565 48.43793973, -5.00151485 48.43791414, -5.00146417 48.43788845, -5.00141361 48.43786265, -5.00136318 48.43783674, -5.00131286 48.43781073, -5.00126267 48.43778462, -5.00121261 48.4377584, -5.00116267 48.43773208, -5.00111285 48.43770565, -5.00106316 48.43767912, -5.00101359 48.43765248, -5.00096415 48.43762574, -5.00091484 48.4375989, -5.00086565 48.43757195, -5.00081659 48.4375449, -5.00076766 48.43751775, -5.00071886 48.4374905, -5.00067018 48.43746314, -5.00062164 48.43743569, -5.00057322 48.43740813, -5.00052494 48.43738047, -5.00047678 48.43735271, -5.00042876 48.43732485, -5.00038087 48.43729689, -5.00033311 48.43726883, -5.00028549 48.43724067, -5.000238 48.43721241, -5.00019064 48.43718405, -5.00014342 48.43715559, -5.00009633 48.43712703, -5.00004937 48.43709838, -5.00000255 48.43706963, -4.99995587 48.43704078, -4.99990932 48.43701183, -4.99986292 48.43698278, -4.99981664 48.43695364, -4.99977051 48.4369244, -4.99972451 48.43689507, -4.99967866 48.43686563, -4.99963294 48.43683611, -4.99958736 48.43680649, -4.99954192 48.43677677, -4.99949663 48.43674696, -4.99945147 48.43671705, -4.99940646 48.43668705, -4.99936158 48.43665695, -4.99931685 48.43662676, -4.99927226 48.43659648, -4.99922782 48.43656611, -4.99918352 48.43653564, -4.99913936 48.43650508, -4.99909535 48.43647443, -4.99905148 48.43644368, -4.99900776 48.43641284, -4.99896419 48.43638192, -4.99892076 48.4363509, -4.99887747 48.43631979, -4.99883434 48.43628859, -4.99879135 48.4362573, -4.99874851 48.43622592, -4.99870582 48.43619445, -4.99866328 48.4361629, -4.99862088 48.43613125, -4.99857864 48.43609951, -4.99853654 48.43606769, -4.9984946 48.43603578, -4.99845281 48.43600378, -4.99841117 48.4359717, -4.99836968 48.43593952, -4.99832834 48.43590726, -4.99828716 48.43587492, -4.99824612 48.43584249, -4.99820525 48.43580997, -4.99816452 48.43577737, -4.99812395 48.43574468, -4.99808353 48.43571191, -4.99804327 48.43567905, -4.99800317 48.43564611, -4.99796322 48.43561309, -4.99792343 48.43557998, -4.99788379 48.43554679, -4.99784431 48.43551352, -4.99780499 48.43548016, -4.99776582 48.43544672, -4.99772681 48.43541321, -4.99768796 48.4353796, -4.99764928 48.43534592, -4.99761075 48.43531216, -4.99757237 48.43527832, -4.99753416 48.43524439, -4.99749611 48.43521039, -4.99745822 48.43517631, -4.9974205 48.43514215, -4.99738293 48.43510791, -4.99734552 48.43507359, -4.99730828 48.43503919, -4.9972712 48.43500472, -4.99723428 48.43497017, -4.99719753 48.43493554, -4.99716094 48.43490084, -4.99712451 48.43486605, -4.99708825 48.4348312, -4.99705216 48.43479626, -4.99701622 48.43476126, -4.99698046 48.43472617, -4.99694486 48.43469101, -4.99690942 48.43465578, -4.99687416 48.43462048, -4.99683906 48.4345851, -4.99680412 48.43454964, -4.99676936 48.43451412, -4.99673476 48.43447852, -4.99670033 48.43444285, -4.99666607 48.43440711, -4.99663198 48.43437129, -4.99659805 48.43433541, -4.9965643 48.43429945, -4.99653072 48.43426343, -4.99649731 48.43422733, -4.99646406 48.43419117, -4.99643099 48.43415493, -4.99639809 48.43411863, -4.99636536 48.43408225, -4.99633281 48.43404581, -4.99630042 48.43400931, -4.99626821 48.43397273, -4.99623617 48.43393609, -4.99620431 48.43389938, -4.99617262 48.4338626, -4.9961411 48.43382576, -4.99610975 48.43378885, -4.99607858 48.43375187, -4.99604759 48.43371484, -4.99601677 48.43367773, -4.99598612 48.43364056, -4.99595566 48.43360333, -4.99592536 48.43356604, -4.99589525 48.43352868, -4.99586531 48.43349126, -4.99583554 48.43345378, -4.99580596 48.43341623, -4.99577655 48.43337862, -4.99574732 48.43334095, -4.99571826 48.43330322, -4.99568939 48.43326544, -4.99566069 48.43322758, -4.99563218 48.43318967, -4.99560384 48.43315171, -4.99557568 48.43311368, -4.9955477 48.43307559, -4.9955199 48.43303744, -4.99549228 48.43299924, -4.99546485 48.43296098, -4.99543759 48.43292266, -4.99541051 48.43288429, -4.99538362 48.43284586, -4.99535691 48.43280737, -4.99533037 48.43276883, -4.99530402 48.43273023, -4.99527786 48.43269157, -4.99525187 48.43265287, -4.99522607 48.4326141, -4.99520045 48.43257529, -4.99517502 48.43253642, -4.99514977 48.4324975, -4.9951247 48.43245852, -4.99509982 48.4324195, -4.99507512 48.43238042, -4.99505061 48.43234129, -4.99502628 48.43230211, -4.99500213 48.43226287, -4.99497817 48.43222359, -4.9949544 48.43218426, -4.99493081 48.43214488, -4.99490741 48.43210545, -4.9948842 48.43206597, -4.99486117 48.43202644, -4.99483833 48.43198687, -4.99481567 48.43194724, -4.99479321 48.43190757, -4.99477093 48.43186785, -4.99474883 48.43182809, -4.99472693 48.43178828, -4.99470521 48.43174843, -4.99468369 48.43170853, -4.99466235 48.43166858, -4.99464119 48.43162859, -4.99462023 48.43158856, -4.99459946 48.43154848, -4.99457888 48.43150836, -4.99455848 48.4314682, -4.99453828 48.43142799, -4.99451826 48.43138774, -4.99449844 48.43134745, -4.99447881 48.43130712, -4.99445936 48.43126675, -4.99444011 48.43122634, -4.99442105 48.43118589, -4.99440218 48.43114539, -4.9943835 48.43110486, -4.99436501 48.43106429, -4.99434671 48.43102368, -4.99432861 48.43098304, -4.9943107 48.43094235, -4.99429298 48.43090163, -4.99427545 48.43086087, -4.99425811 48.43082008, -4.99424097 48.43077925, -4.99422402 48.43073838, -4.99420726 48.43069748, -4.9941907 48.43065655, -4.99417433 48.43061557, -4.99415815 48.43057457, -4.99414217 48.43053353, -4.99412638 48.43049246, -4.99411079 48.43045135, -4.99409539 48.43041022, -4.99408018 48.43036905, -4.99406517 48.43032785, -4.99405035 48.43028662, -4.99403573 48.43024535, -4.9940213 48.43020406, -4.99400706 48.43016274, -4.99399303 48.43012139, -4.99397918 48.43008, -4.99396554 48.43003859, -4.99395208 48.42999716, -4.99393883 48.42995569, -4.99392577 48.4299142, -4.9939129 48.42987267, -4.99390024 48.42983113, -4.99388776 48.42978955, -4.99387549 48.42974795, -4.99386341 48.42970633, -4.99385153 48.42966468, -4.99383984 48.429623, -4.99382835 48.4295813, -4.99381706 48.42953958, -4.99380597 48.42949783, -4.99379507 48.42945606, -4.99378437 48.42941427, -4.99377386 48.42937246, -4.99376356 48.42933062, -4.99375345 48.42928876, -4.99374354 48.42924688, -4.99373383 48.42920499, -4.99372431 48.42916307, -4.99371499 48.42912113, -4.99370587 48.42907917, -4.99369695 48.42903719, -4.99368823 48.4289952, -4.99367971 48.42895318, -4.99367138 48.42891115, -4.99366325 48.42886911, -4.99365532 48.42882704, -4.99364759 48.42878496, -4.99364006 48.42874286, -4.99363273 48.42870075, -4.99362559 48.42865862, -4.99361866 48.42861648, -4.99361192 48.42857432, -4.99360539 48.42853215)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon - val firstMission = - MissionDTO( - mission = - MissionEntity( - id = 10, - missionTypes = listOf(MissionTypeEnum.LAND), - openBy = "KIM", - closedBy = "TRA", - facade = "NAMO", - observationsCacem = - "Remain vote several ok. Bring American play woman challenge. Throw low law positive seven.", - startDateTimeUtc = - ZonedDateTime.parse("2022-03-21T12:11:13Z"), - endDateTimeUtc = null, - geom = polygon, - isClosed = false, - isDeleted = false, - envActions = listOf(), - missionSource = MissionSourceEnum.MONITORENV, - hasMissionOrder = false, - isUnderJdp = false, + val newMissionUpdated = + jpaMissionRepository.save( + newMission.copy( controlUnits = listOf( LegacyControlUnitEntity( id = 10002, - administration = "DDTM", - isArchived = false, name = "DML 2A", + administration = "DIRM / DM", + isArchived = false, resources = listOf( LegacyControlUnitResourceEntity( @@ -650,74 +576,159 @@ class JpaMissionRepositoryITests : AbstractDBTests() { name = "Semi-rigide 1", ), - LegacyControlUnitResourceEntity( - id = 4, - controlUnitId = - 10002, - name = - "Semi-rigide 2", - ), LegacyControlUnitResourceEntity( id = 5, controlUnitId = 10002, - name = - "Voiture", + name = "Voiture", ), ), ), ), - isGeometryComputedFromControls = false, ), ) - val mission = jpaMissionRepository.findFullMissionById(10) - assertThat(mission).isEqualTo(firstMission) + // Then + assertThat(newMissionUpdated.mission.controlUnits).hasSize(1) + assertThat(newMissionUpdated.mission.controlUnits.first().id).isEqualTo(10002) + assertThat(newMissionUpdated.mission.controlUnits.first().name).isEqualTo("DML 2A") + assertThat(newMissionUpdated.mission.controlUnits.first().administration) + .isEqualTo("DIRM / DM") + assertThat(newMissionUpdated.mission.controlUnits.first().resources).hasSize(2) + assertThat(newMissionUpdated.mission.controlUnits.first().resources.first().id).isEqualTo(3) + assertThat(newMissionUpdated.mission.controlUnits.first().resources.first().controlUnitId) + .isEqualTo(10002) + assertThat(newMissionUpdated.mission.controlUnits.first().resources.first().name) + .isEqualTo("Semi-rigide 1") + assertThat(newMissionUpdated.mission.controlUnits.first().resources.last().id).isEqualTo(5) + assertThat(newMissionUpdated.mission.controlUnits.first().resources.last().controlUnitId) + .isEqualTo(10002) + assertThat(newMissionUpdated.mission.controlUnits.first().resources.last().name) + .isEqualTo("Voiture") + } + + @Test + @Transactional + fun `save should update existing mission with existing resources`() { + // Given + val mission = jpaMissionRepository.findById(25) + val newControlUnitResource = jpaControlUnitResourceRepository.findById(10) + val newControlUnit = + jpaControlUnitRepository.findById( + requireNotNull(newControlUnitResource.controlUnit.id), + ) + + val nextMission = + mission.copy( + controlUnits = + mission.controlUnits.plus( + LegacyControlUnitEntity( + id = requireNotNull(newControlUnit.controlUnit.id), + administration = newControlUnit.administration.name, + isArchived = newControlUnit.controlUnit.isArchived, + name = newControlUnit.controlUnit.name, + resources = + listOf( + newControlUnitResource + .toLegacyControlUnitResource(), + ), + contact = null, + ), + ), + ) + + val updatedMission = jpaMissionRepository.save(nextMission) + + assertThat(updatedMission.mission.controlUnits).hasSize(2) + assertThat(updatedMission.mission.controlUnits.first().id).isEqualTo(10002) + assertThat(updatedMission.mission.controlUnits.first().resources).hasSize(1) + assertThat(updatedMission.mission.controlUnits.first().resources.first().id).isEqualTo(3) + assertThat(updatedMission.mission.controlUnits.first().resources.first().controlUnitId) + .isEqualTo(10002) + assertThat(updatedMission.mission.controlUnits.last().id).isEqualTo(10018) + assertThat(updatedMission.mission.controlUnits.last().resources).hasSize(1) + assertThat(updatedMission.mission.controlUnits.last().resources.first().id).isEqualTo(10) + assertThat(updatedMission.mission.controlUnits.last().resources.first().controlUnitId) + .isEqualTo(10018) } @Test @Transactional - fun `findFullMissionById Should return specified mission and envActionReportingIds with multiple reportings attached`() { + fun `save should throw an exception When the resource id is not found`() { + // Given + val newMission = + MissionEntity( + missionTypes = listOf(MissionTypeEnum.SEA), + startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), + isClosed = false, + isDeleted = false, + missionSource = MissionSourceEnum.MONITORENV, + hasMissionOrder = false, + isUnderJdp = false, + controlUnits = + listOf( + LegacyControlUnitEntity( + id = 5, + name = "DPM – DDTM 35", + administration = "DDTM", + isArchived = false, + resources = + listOf( + LegacyControlUnitResourceEntity( + id = 123456, + controlUnitId = 5, + name = "PAM Jeanne Barret", + ), + ), + ), + ), + isGeometryComputedFromControls = false, + ) + // When - val missionDTO = jpaMissionRepository.findFullMissionById(53) - assertThat(missionDTO.mission.id).isEqualTo(53) - assertThat(missionDTO.mission.envActions).hasSize(3) - assertThat( - missionDTO.envActionsAttachedToReportingIds?.get(0)?.first, - ) - .isEqualTo(UUID.fromString("9969413b-b394-4db4-985f-b00743ffb833")) - assertThat(missionDTO.envActionsAttachedToReportingIds?.get(0)?.second) - .isEqualTo(listOf(11, 9)) - assertThat( - missionDTO.envActionsAttachedToReportingIds?.get(1)?.first, - ) - .isEqualTo(UUID.fromString("3480657f-7845-4eb4-aa06-07b174b1da45")) - assertThat(missionDTO.envActionsAttachedToReportingIds?.get(1)?.second) - .isEqualTo(listOf(10)) + val throwable = catchThrowable { jpaMissionRepository.save(newMission) } + + // Then + assertThat(throwable).isInstanceOf(InvalidDataAccessApiUsageException::class.java) } @Test @Transactional - fun `findById Should return specified mission and associated env actions and associated envActionReportingIds`() { + fun `save should throw an exception When the unit id is not found`() { + // Given + val newMission = + MissionEntity( + missionTypes = listOf(MissionTypeEnum.SEA), + startDateTimeUtc = ZonedDateTime.parse("2022-01-15T04:50:09Z"), + isClosed = false, + isDeleted = false, + missionSource = MissionSourceEnum.MONITORENV, + hasMissionOrder = false, + isUnderJdp = false, + controlUnits = + listOf( + LegacyControlUnitEntity( + id = 123456, + name = "PAM Jeanne Barret", + administration = "", + isArchived = false, + resources = listOf(), + ), + ), + isGeometryComputedFromControls = false, + ) + // When - val missionDTO = jpaMissionRepository.findFullMissionById(34) - assertThat(missionDTO.mission.id).isEqualTo(34) - assertThat(missionDTO.mission.envActions).hasSize(2) - assertThat( - missionDTO.envActionsAttachedToReportingIds?.get(0)?.first, - ) - .isEqualTo(UUID.fromString("b8007c8a-5135-4bc3-816f-c69c7b75d807")) - assertThat(missionDTO.envActionsAttachedToReportingIds?.get(0)?.second).isEqualTo(listOf(6)) + val throwable = catchThrowable { jpaMissionRepository.save(newMission) } + + // Then + assertThat(throwable).isInstanceOf(DataIntegrityViolationException::class.java) } @Test @Transactional fun `save Should update mission`() { // Given - val wktReader = WKTReader() - val multipolygonString = - "MULTIPOLYGON (((-4.54877816747593 48.305559876971, -4.54997332394943 48.3059760121399, -4.54998501370013 48.3071882334181, -4.54879290083417 48.3067746138142, -4.54877816747593 48.305559876971)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon val infraction = InfractionEntity( id = UUID.randomUUID().toString(), @@ -736,14 +747,6 @@ class JpaMissionRepositoryITests : AbstractDBTests() { val controlAction = EnvActionControlEntity( id = UUID.randomUUID(), - themes = - listOf( - ThemeEntity( - theme = "5", - subThemes = listOf("4"), - protectedSpecies = listOf("5"), - ), - ), observations = "RAS", actionNumberOfControls = 12, actionTargetType = ActionTargetTypeEnum.VEHICLE, @@ -753,14 +756,6 @@ class JpaMissionRepositoryITests : AbstractDBTests() { val surveillanceAction = EnvActionSurveillanceEntity( id = UUID.randomUUID(), - themes = - listOf( - ThemeEntity( - theme = "6", - subThemes = listOf("7"), - protectedSpecies = listOf("8"), - ), - ), observations = "This is a surveillance action", ) val noteAction = @@ -828,10 +823,6 @@ class JpaMissionRepositoryITests : AbstractDBTests() { @Transactional fun `save Should update mission with associated envActions`() { // Given - val wktReader = WKTReader() - val multipolygonString = - "MULTIPOLYGON (((-4.54877816747593 48.305559876971, -4.54997332394943 48.3059760121399, -4.54998501370013 48.3071882334181, -4.54879290083417 48.3067746138142, -4.54877816747593 48.305559876971)))" - val polygon = wktReader.read(multipolygonString) as MultiPolygon val envAction = EnvActionControlEntity( @@ -889,40 +880,41 @@ class JpaMissionRepositoryITests : AbstractDBTests() { @Test @Transactional - fun `delete Should set the deleted flag as true`() { - // Given - val missionsList = - jpaMissionRepository.findAllFullMissions( - startedAfter = ZonedDateTime.parse("2022-01-01T10:54:00Z").toInstant(), - startedBefore = ZonedDateTime.parse("2022-08-08T00:00:00Z").toInstant(), - missionTypes = null, - missionStatuses = null, - seaFronts = null, - pageable = Pageable.unpaged(), - ) - assertThat(missionsList).hasSize(21) - - // When - jpaMissionRepository.delete(3) - - // Then - val nextMissionList = - jpaMissionRepository.findAllFullMissions( - startedAfter = ZonedDateTime.parse("2022-01-01T10:54:00Z").toInstant(), - startedBefore = ZonedDateTime.parse("2022-08-08T00:00:00Z").toInstant(), - missionTypes = null, - missionStatuses = null, - seaFronts = null, - pageable = Pageable.unpaged(), - ) - assertThat(nextMissionList).hasSize(20) - } - - @Test - @Transactional - fun `findByIds() should find the matching missions`() { - val foundMissions = jpaMissionRepository.findByIds(listOf(50, 51, 52)) - - assertThat(foundMissions).hasSize(3) + fun `save Should update subThemes of envActions`() { + val mission = jpaMissionRepository.findById(34) + val envAction = mission.envActions?.find { it.id == UUID.fromString("b8007c8a-5135-4bc3-816f-c69c7b75d807") } + assertThat(envAction?.controlPlans?.size).isEqualTo(1) + assertThat(envAction?.controlPlans?.get(0)?.subThemeIds?.size).isEqualTo(1) + val nextControlPlans = listOf( + EnvActionControlPlanEntity( + subThemeIds = listOf(53, 34), + themeId = 2, + ), + EnvActionControlPlanEntity( + tagIds = listOf(1, 2, 3), + themeId = 11, + ), + EnvActionControlPlanEntity( + themeId = 17, + ), + ) + val nextMission = mission.copy( + envActions = mission.envActions?.map { + if (it.id == UUID.fromString("b8007c8a-5135-4bc3-816f-c69c7b75d807") && it is EnvActionControlEntity) { + it.copy(controlPlans = nextControlPlans) + } else { + it + } + }, + ) + val updatedMission = jpaMissionRepository.save(nextMission) + val updatedControlPlan = updatedMission.mission.envActions?.find { + it.id == UUID.fromString("b8007c8a-5135-4bc3-816f-c69c7b75d807") + }?.controlPlans + assertThat(updatedControlPlan?.size).isEqualTo(3) + assertThat(updatedControlPlan?.get(0)?.subThemeIds?.size).isEqualTo(2) + assertThat(updatedControlPlan?.get(0)?.subThemeIds?.get(0)).isEqualTo(53) + assertThat(updatedControlPlan?.get(1)?.tagIds?.size).isEqualTo(3) + assertThat(updatedControlPlan?.get(1)?.tagIds?.get(0)).isEqualTo(1) } } diff --git a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepositoryITests.kt.kt b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepositoryITests.kt.kt index 0d9fb45648..7dd9a52761 100644 --- a/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepositoryITests.kt.kt +++ b/backend/src/test/kotlin/fr/gouv/cacem/monitorenv/infrastructure/database/repositories/JpaReportingRepositoryITests.kt.kt @@ -261,8 +261,8 @@ class JpaReportingRepositoryITests : AbstractDBTests() { seaFront = "NAMO", description = "Test reporting", reportType = ReportingTypeEnum.INFRACTION_SUSPICION, - theme = "Police des mouillages", - subThemes = listOf("ZMEL"), + themeId = 12, + subThemeIds = listOf(82), actionTaken = "Aucune", isControlRequired = false, hasNoUnitAvailable = false, @@ -289,8 +289,8 @@ class JpaReportingRepositoryITests : AbstractDBTests() { assertThat(reportingDTO.reporting.description).isEqualTo("Test reporting") assertThat(reportingDTO.reporting.reportType) .isEqualTo(ReportingTypeEnum.INFRACTION_SUSPICION) - assertThat(reportingDTO.reporting.theme).isEqualTo("Police des mouillages") - assertThat(reportingDTO.reporting.subThemes).isEqualTo(listOf("ZMEL")) + assertThat(reportingDTO.reporting.themeId).isEqualTo(12) + assertThat(reportingDTO.reporting.subThemeIds).isEqualTo(listOf(82)) assertThat(reportingDTO.reporting.actionTaken).isEqualTo("Aucune") assertThat(reportingDTO.reporting.isControlRequired).isEqualTo(false) assertThat(reportingDTO.reporting.hasNoUnitAvailable).isEqualTo(false) diff --git a/frontend/cypress/e2e/side_window/mission_form/main_form.spec.ts b/frontend/cypress/e2e/side_window/mission_form/main_form.spec.ts index becce470c5..c7d6b9c19d 100644 --- a/frontend/cypress/e2e/side_window/mission_form/main_form.spec.ts +++ b/frontend/cypress/e2e/side_window/mission_form/main_form.spec.ts @@ -296,7 +296,7 @@ context('Side Window > Mission Form > Main Form', () => { const month = new Date().getMonth() cy.fill('Période spécifique', [ [2023, month - 4, 1], - [2023, month - 4, 31] + [2023, month - 3, 31] ]) cy.wait('@getMissions') diff --git a/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts b/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts index 47a214eb58..ee8b1c44aa 100644 --- a/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts +++ b/frontend/cypress/e2e/side_window/mission_form/mission_actions.spec.ts @@ -43,29 +43,28 @@ context('Mission actions', () => { }) }) - it('allow only one theme and may be multiple subthemes in control actions', () => { + it('allow only one theme and multiple subthemes in control actions', () => { // Given cy.get('*[data-cy="edit-mission-34"]').click({ force: true }) cy.get('*[data-cy="action-card"]').eq(1).click() cy.get('*[data-cy="envaction-theme-element"]').should('have.length', 1) - cy.get('*[data-cy="envaction-theme-selector"]').contains('Police des mouillages') - cy.get('*[data-cy="envaction-theme-element"]').contains('Mouillage individuel') - cy.get('*[data-cy="envaction-theme-element"]').contains('ZMEL') - cy.get('*[data-cy="envaction-protected-species-selector"]').should('not.exist') + cy.get('*[data-cy="envaction-theme-selector"]').contains('Mouillage individuel') // id 100 + cy.get('*[data-cy="envaction-theme-element"]').contains('Mouillage avec AOT individuelle') // id 102 + cy.get('*[data-cy="envaction-tags-selector"]').should('not.exist') // When cy.get('*[data-cy="envaction-theme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Police des espèces protégées').click() + cy.get('*[data-cy="envaction-theme-element"]').contains('Espèce protégée').click() // id 103 cy.get('*[data-cy="envaction-subtheme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Perturbation').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Atteinte aux habitats').click({ force: true }) + cy.get('*[data-cy="envaction-theme-element"]').contains('Destruction, capture, arrachage').click({ force: true }) // id 117 + cy.get('*[data-cy="envaction-theme-element"]').contains('Détention des espèces protégées').click({ force: true }) // id 120 cy.get('*[data-cy="envaction-subtheme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-protected-species-selector"]').should('exist') - cy.get('*[data-cy="envaction-protected-species-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Habitat').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Oiseaux').click({ force: true }) - cy.get('*[data-cy="envaction-protected-species-selector"]').click({ force: true }) + cy.get('*[data-cy="envaction-tags-selector"]').should('exist') + cy.get('*[data-cy="envaction-tags-selector"]').click({ force: true }) + cy.get('*[data-cy="envaction-theme-element"]').contains('Habitat').click({ force: true }) // id 15 + cy.get('*[data-cy="envaction-theme-element"]').contains('Oiseaux').click({ force: true }) // id 11 + cy.get('*[data-cy="envaction-tags-selector"]').click({ force: true }) cy.get('*[data-cy="envaction-add-theme"]').should('not.exist') @@ -76,15 +75,17 @@ context('Mission actions', () => { cy.wait('@updateMission').then(({ request, response }) => { expect(response && response.statusCode).equal(200) - const { themes } = request.body.envActions.find(a => a.id === 'b8007c8a-5135-4bc3-816f-c69c7b75d807') - expect(themes.length).equal(1) - expect(themes[0].theme).equal('Police des espèces protégées et de leurs habitats (faune et flore)') - expect(themes[0].subThemes.length).equal(2) - expect(themes[0].subThemes[0]).equal("Perturbation d'animaux") - expect(themes[0].subThemes[1]).equal("Atteinte aux habitats d'espèces protégées") - expect(themes[0].protectedSpecies.length).equal(2) - expect(themes[0].protectedSpecies[0]).equal('HABITAT') - expect(themes[0].protectedSpecies[1]).equal('BIRDS') + const { controlPlans } = request.body.envActions.find(a => a.id === 'b8007c8a-5135-4bc3-816f-c69c7b75d807') + + expect(controlPlans.length).equal(1) + expect(controlPlans[0].themeId).equal(103) + + expect(controlPlans[0].subThemeIds.length).equal(2) + expect(controlPlans[0].subThemeIds[0]).equal(117) + expect(controlPlans[0].subThemeIds[1]).equal(120) + expect(controlPlans[0].tagIds.length).equal(2) + expect(controlPlans[0].tagIds[0]).equal(11) + expect(controlPlans[0].tagIds[1]).equal(15) }) }) @@ -114,31 +115,29 @@ context('Mission actions', () => { }) }) - it('allow multiple themes and may be multiple subthemes in surveillance actions', () => { + it('allow multiple themes and multiple subthemes in surveillance actions', () => { // Given cy.get('*[data-cy="edit-mission-34"]').click({ force: true }) cy.get('*[data-cy="action-card"]').eq(0).click() cy.get('*[data-cy="envaction-theme-element"]').should('have.length', 2) - cy.get('*[data-cy="envaction-theme-selector"]') - .eq(0) - .contains('Police des espèces protégées et de leurs habitats (faune et flore)') - cy.get('*[data-cy="envaction-theme-element"]').contains('Destruction, capture, arrachage') - cy.get('*[data-cy="envaction-protected-species-selector"]').should('exist') - cy.get('*[data-cy="envaction-theme-element"]').contains('Flore') - cy.get('*[data-cy="envaction-theme-element"]').contains('Oiseaux') + cy.get('*[data-cy="envaction-theme-selector"]').eq(0).contains('Espèce protégée et leur habitat (faune et flore)') // id 103 + cy.get('*[data-cy="envaction-theme-element"]').contains('Destruction, capture, arrachage') // id 117 + cy.get('*[data-cy="envaction-tags-selector"]').should('exist') + cy.get('*[data-cy="envaction-theme-element"]').contains('Habitat') // id 15 + cy.get('*[data-cy="envaction-theme-element"]').contains('Oiseaux') // id 11 // When cy.get('*[data-cy="envaction-theme-selector"]').eq(0).click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').eq(0).contains('Police des réserves naturelles').click() + cy.get('*[data-cy="envaction-theme-element"]').eq(0).contains('Épave').click({ force: true }) // id 105 cy.get('*[data-cy="envaction-add-theme"]').click({ force: true }) cy.get('*[data-cy="envaction-theme-selector"]').eq(2).click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').eq(2).contains('Rejets illicites').click() + cy.get('*[data-cy="envaction-theme-element"]').eq(2).contains('Rejet').click() // id 102 cy.get('*[data-cy="envaction-subtheme-selector"]').eq(2).click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').eq(2).contains('Jet de déchet').click({ force: true }) + cy.get('*[data-cy="envaction-theme-element"]').eq(2).contains("Rejet d'hydrocarbure").click({ force: true }) // id 74 - cy.get('*[data-cy="envaction-protected-species-selector"]').should('have.length', 0) + cy.get('*[data-cy="envaction-tags-selector"]').should('have.length', 0) cy.intercept('PUT', `/bff/v1/missions/34`).as('updateMission') cy.clickButton('Enregistrer et quitter') @@ -147,20 +146,24 @@ context('Mission actions', () => { cy.wait('@updateMission').then(({ response }) => { expect(response && response.statusCode).equal(200) - const { themes } = response && response.body.envActions.find(a => a.id === 'c52c6f20-e495-4b29-b3df-d7edfb67fdd7') - expect(themes.length).equal(3) - expect(themes[0].theme).equal('Police des réserves naturelles') - expect(themes[0].subThemes.length).equal(0) - expect(themes[0].protectedSpecies.length).equal(0) - expect(themes[1].theme).equal('Police des mouillages') - expect(themes[1].subThemes.length).equal(2) - expect(themes[1].subThemes[0]).equal('Mouillage individuel') - expect(themes[1].subThemes[1]).equal('ZMEL') - expect(themes[1].protectedSpecies.length).equal(0) - expect(themes[2].theme).equal('Rejets illicites') - expect(themes[2].subThemes.length).equal(1) - expect(themes[2].subThemes[0]).equal('Jet de déchet') - expect(themes[2].protectedSpecies.length).equal(0) + const { controlPlans } = + response && response.body.envActions.find(a => a.id === 'c52c6f20-e495-4b29-b3df-d7edfb67fdd7') + expect(controlPlans.length).equal(3) + + expect(controlPlans[0].themeId).equal(100) + expect(controlPlans[0].subThemeIds.length).equal(2) + expect(controlPlans[0].subThemeIds[0]).equal(100) + expect(controlPlans[0].subThemeIds[1]).equal(102) + expect(controlPlans[0].tagIds.length).equal(0) + 0 + expect(controlPlans[1].themeId).equal(105) + expect(controlPlans[1].subThemeIds.length).equal(0) + expect(controlPlans[1].tagIds.length).equal(0) + + expect(controlPlans[2].themeId).equal(102) + expect(controlPlans[2].subThemeIds.length).equal(1) + expect(controlPlans[2].subThemeIds[0]).equal(110) + expect(controlPlans[2].tagIds.length).equal(0) }) }) diff --git a/frontend/cypress/e2e/side_window/mission_form/mission_dates_validation.spec.ts b/frontend/cypress/e2e/side_window/mission_form/mission_dates_validation.spec.ts index 55657cf4f1..8b27f2a758 100644 --- a/frontend/cypress/e2e/side_window/mission_form/mission_dates_validation.spec.ts +++ b/frontend/cypress/e2e/side_window/mission_form/mission_dates_validation.spec.ts @@ -37,9 +37,9 @@ context('Mission dates', () => { cy.clickButton('Ajouter une surveillance') cy.get('*[data-cy="envaction-theme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Police des espèces protégées').click() + cy.get('*[data-cy="envaction-theme-element"]').contains('Espèce protégée').click() cy.get('*[data-cy="envaction-subtheme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Perturbation').click({ force: true }) + cy.get('*[data-cy="envaction-theme-element"]').contains('Destruction').click({ force: true }) cy.get('*[data-cy="envaction-subtheme-selector"]').click('topLeft', { force: true }) cy.getDataCy('surveillance-duration-matches-mission').should('have.class', 'rs-checkbox-checked') @@ -94,9 +94,9 @@ context('Mission dates', () => { cy.clickButton('Ajouter une surveillance') cy.get('*[data-cy="envaction-theme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Police des mouillages').click() + cy.get('*[data-cy="envaction-theme-element"]').contains('Mouillage individuel').click() cy.get('*[data-cy="envaction-subtheme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('ZMEL').click({ force: true }) + cy.get('*[data-cy="envaction-theme-element"]').contains('Autre').click({ force: true }) cy.get('*[data-cy="envaction-subtheme-selector"]').click('topLeft', { force: true }) cy.getDataCy('action-card').eq(0).click() @@ -218,9 +218,9 @@ context('Mission dates', () => { cy.clickButton('Ajouter des contrôles') cy.get('*[data-cy="envaction-theme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Police des espèces protégées').click() + cy.get('*[data-cy="envaction-theme-element"]').contains('Espèce protégée').click() cy.get('*[data-cy="envaction-subtheme-selector"]').click({ force: true }) - cy.get('*[data-cy="envaction-theme-element"]').contains('Perturbation').click({ force: true }) + cy.get('*[data-cy="envaction-theme-element"]').contains('Détention').click({ force: true }) cy.get('*[data-cy="envaction-theme-element"]').click('topLeft') cy.get('*[data-cy="envaction-subtheme-selector"]').click('topLeft', { force: true }) diff --git a/frontend/cypress/e2e/side_window/mission_list/missions.spec.ts b/frontend/cypress/e2e/side_window/mission_list/missions.spec.ts index ba64bd51d5..442c16589f 100644 --- a/frontend/cypress/e2e/side_window/mission_list/missions.spec.ts +++ b/frontend/cypress/e2e/side_window/mission_list/missions.spec.ts @@ -54,10 +54,10 @@ context('Missions', () => { cy.log('Should filter by theme') cy.fill('Thématique', ['Police des épaves']) - cy.get('*[data-cy="cell-envactions-themes"]') + cy.get('*[data-cy="cell-envActions-themes"]') .eq(0) .contains( - 'Police des activités de cultures marines : Contrôle du schéma des structures ; Police des épaves : Épave/navire abandonné / Contrôle administratif' + 'Police des activités de cultures marines : Contrôle du schéma des structures ; Police des épaves : Contrôle administratif / Épave/navire abandonné' ) }) }) diff --git a/frontend/cypress/e2e/side_window/reporting/filters.spec.ts b/frontend/cypress/e2e/side_window/reporting/filters.spec.ts index dfddaa5ae0..e8a5d8c2b0 100644 --- a/frontend/cypress/e2e/side_window/reporting/filters.spec.ts +++ b/frontend/cypress/e2e/side_window/reporting/filters.spec.ts @@ -40,8 +40,9 @@ context('Reportings', () => { }) it('Should filter reportings by source', () => { + cy.wait(1000) cy.fill('Source', ['Sémaphore de Fécamp']) - + cy.wait(500) cy.getDataCy('reportings-filter-tags').find('.Component-SingleTag > span').contains('Source Sémaphore de Fécamp') cy.get('.Table-SimpleTable tr').should('have.length.to.be.greaterThan', 0) @@ -59,6 +60,7 @@ context('Reportings', () => { it('Should filter reportings by type', () => { cy.fill('Type de signalement', 'Observation') + cy.wait(500) cy.wait('@getReportings') cy.get('.Table-SimpleTable tr').should('have.length.to.be.greaterThan', 0) diff --git a/frontend/src/api/controlPlans.ts b/frontend/src/api/controlPlans.ts new file mode 100644 index 0000000000..5c33b45e5d --- /dev/null +++ b/frontend/src/api/controlPlans.ts @@ -0,0 +1,18 @@ +import { monitorenvPrivateApi } from './api' + +import type { ControlPlans } from '../domain/entities/controlPlan' + +export const controlPlansAPI = monitorenvPrivateApi.injectEndpoints({ + endpoints: build => ({ + getControlPlans: build.query({ + keepUnusedDataFor: 28800, // 8 hours + query: () => '/v1/control_plans' + }), + getControlPlansByYear: build.query({ + keepUnusedDataFor: 28800, // 8 hours + query: year => `/v1/control_plans/${year}` + }) + }) +}) + +export const { useGetControlPlansByYearQuery, useGetControlPlansQuery } = controlPlansAPI diff --git a/frontend/src/api/missionsAPI.ts b/frontend/src/api/missionsAPI.ts index d59314db67..cd852ed1bc 100644 --- a/frontend/src/api/missionsAPI.ts +++ b/frontend/src/api/missionsAPI.ts @@ -4,7 +4,7 @@ import { monitorenvPrivateApi, monitorenvPublicApi } from './api' import { ControlUnit } from '../domain/entities/controlUnit' import { addNewMissionListener, missionEventListener } from '../features/missions/MissionForm/sse' -import type { Mission, MissionForApi } from '../domain/entities/missions' +import type { Mission, MissionData } from '../domain/entities/missions' type MissionsResponse = Mission[] type MissionsFilter = { @@ -30,7 +30,7 @@ const getSeaFrontsFilter = seaFronts => export const missionsAPI = monitorenvPrivateApi.injectEndpoints({ endpoints: builder => ({ - createMission: builder.mutation({ + createMission: builder.mutation({ invalidatesTags: (_, __, { attachedReportingIds = [] }) => [ { id: 'LIST', type: 'Missions' }, { id: 'LIST', type: 'Reportings' }, @@ -88,7 +88,7 @@ export const missionsAPI = monitorenvPrivateApi.injectEndpoints({ .filter(v => v) .join('&') }), - updateMission: builder.mutation({ + updateMission: builder.mutation({ invalidatesTags: (_, __, { attachedReportingIds = [], detachedReportingIds = [], id }) => [ { id, type: 'Missions' }, { id: 'LIST', type: 'Missions' }, diff --git a/frontend/src/domain/entities/controlPlan.ts b/frontend/src/domain/entities/controlPlan.ts new file mode 100644 index 0000000000..c0e51a177b --- /dev/null +++ b/frontend/src/domain/entities/controlPlan.ts @@ -0,0 +1,41 @@ +export type ControlPlans = { + subThemes: ControlPlansSubThemeCollection + tags: ControlPlansTagCollection + themes: ControlPlansThemeCollection +} + +export type ControlPlansThemeCollection = { + [key: number]: ControlPlansTheme +} + +export type ControlPlansTheme = { + id: number + theme: string +} + +export type ControlPlansSubThemeCollection = { + [key: number]: ControlPlansSubTheme +} + +export type ControlPlansSubTheme = { + id: number + subTheme: string + themeId: number + year: number +} + +export type ControlPlansTagCollection = { + [key: number]: ControlPlansTag +} + +export type ControlPlansTag = { + id: number + tag: string + themeId: number +} + +export type ControlPlansData = { + subThemeIds: number[] + tagIds: number[] + themeId: number | undefined +} diff --git a/frontend/src/domain/entities/missions.ts b/frontend/src/domain/entities/missions.ts index 6837ec6ded..b63f7c6045 100644 --- a/frontend/src/domain/entities/missions.ts +++ b/frontend/src/domain/entities/missions.ts @@ -1,5 +1,6 @@ import { THEME, customDayjs } from '@mtes-mct/monitor-ui' +import type { ControlPlansData } from './controlPlan' import type { LegacyControlUnit } from './legacyControlUnit' import type { ReportingDetailed } from './reporting' import type { SeaFrontEnum } from './seaFrontType' @@ -158,33 +159,6 @@ export const vesselSizeEnum = { } } -export const protectedSpeciesEnum = { - BIRDS: { - label: 'Oiseaux', - value: 'BIRDS' - }, - FLORA: { - label: 'Flore', - value: 'FLORA' - }, - HABITAT: { - label: 'Habitat', - value: 'HABITAT' - }, - MARINE_MAMMALS: { - label: 'Mammifères marins', - value: 'MARINE_MAMMALS' - }, - OTHER: { - label: 'Autres espèces protégées', - value: 'OTHER' - }, - REPTILES: { - label: 'Reptiles', - value: 'REPTILES' - } -} - export enum MissionStatusEnum { CLOSED = 'CLOSED', ENDED = 'ENDED', @@ -246,8 +220,6 @@ export enum MissionSourceLabel { MONITORFISH = 'CNSP' } -export const THEME_REQUIRE_PROTECTED_SPECIES = ['Police des espèces protégées et de leurs habitats (faune et flore)'] - export const relevantCourtEnum = { JULIS: { code: 'JULIS', @@ -271,6 +243,7 @@ export type ResourceUnit = { administration: string } +// Mission from API export type Mission = { attachedReportingIds: number[] attachedReportings: ReportingDetailed[] @@ -297,8 +270,9 @@ export type Mission, 'controlUnits' | 'facade' | 'id'> & { controlUnits: Array> } +// Mission for API +export type MissionData = Omit>, 'attachedReportings'> -export type MissionForApi = Omit, 'attachedReportings'> export type EnvAction = EnvActionControl | EnvActionSurveillance | EnvActionNote export type NewEnvAction = NewEnvActionControl | EnvActionSurveillance | EnvActionNote @@ -307,16 +281,12 @@ export type EnvActionCommonProperties = { id: string } -export type EnvActionTheme = { - protectedSpecies?: string[] - subThemes: string[] - theme: string -} export type NewEnvActionControl = EnvActionCommonProperties & { actionEndDateTimeUtc?: string | null actionNumberOfControls?: number actionTargetType?: string actionType: ActionTypeEnum.CONTROL + controlPlans: ControlPlansData[] geom?: Record[] infractions: Infraction[] isAdministrativeControl?: boolean @@ -325,7 +295,6 @@ export type NewEnvActionControl = EnvActionCommonProperties & { isSeafarersControl?: boolean observations: string | null reportingIds: number[] - themes: EnvActionTheme[] vehicleType?: string } export type EnvActionControl = NewEnvActionControl & { @@ -335,12 +304,12 @@ export type EnvActionControl = NewEnvActionControl & { export type EnvActionSurveillance = EnvActionCommonProperties & { actionEndDateTimeUtc?: string | null actionType: ActionTypeEnum.SURVEILLANCE + controlPlans: ControlPlansData[] coverMissionZone?: boolean durationMatchesMission?: boolean geom?: Record[] observations: string | null reportingIds: number[] - themes: EnvActionTheme[] } export type EnvActionNote = EnvActionCommonProperties & { diff --git a/frontend/src/domain/entities/reporting.ts b/frontend/src/domain/entities/reporting.ts index bd7f12343f..0749bf58e1 100644 --- a/frontend/src/domain/entities/reporting.ts +++ b/frontend/src/domain/entities/reporting.ts @@ -26,10 +26,10 @@ export type Reporting = { semaphoreId?: number sourceName?: string sourceType: ReportingSourceEnum - subThemes?: string[] + subThemeIds?: number[] targetDetails?: TargetDetails[] targetType?: ReportingTargetTypeEnum - theme?: string + themeId?: number validityTime?: number vehicleType?: string } diff --git a/frontend/src/domain/shared_slices/MissionFilters.ts b/frontend/src/domain/shared_slices/MissionFilters.ts index 024e6938eb..ce4361a4c0 100644 --- a/frontend/src/domain/shared_slices/MissionFilters.ts +++ b/frontend/src/domain/shared_slices/MissionFilters.ts @@ -30,7 +30,7 @@ type MissionFilterValues = { selectedPeriod: string selectedSeaFronts: string[] | undefined selectedStatuses: string[] | undefined - selectedThemes: string[] | undefined + selectedThemes: number[] | undefined startedAfter?: string startedBefore?: string } diff --git a/frontend/src/domain/shared_slices/ReportingsFilters.ts b/frontend/src/domain/shared_slices/ReportingsFilters.ts index c016ca0eb2..3f5277bfdf 100644 --- a/frontend/src/domain/shared_slices/ReportingsFilters.ts +++ b/frontend/src/domain/shared_slices/ReportingsFilters.ts @@ -37,8 +37,8 @@ type ReportingsFiltersSliceType = { startedAfter: string startedBefore?: string statusFilter: string[] - subThemesFilter: string[] | undefined - themeFilter: string[] | undefined + subThemesFilter: number[] | undefined + themeFilter: number[] | undefined typeFilter?: string | undefined } @@ -58,13 +58,13 @@ const initialState: ReportingsFiltersSliceType = { } const persistConfig = { - key: 'reportingsFilters', + key: 'reportingFilters', storage } const reportingFiltersSlice = createSlice({ initialState, - name: 'reportingsFilters', + name: 'reportingFilters', reducers: { resetReportingsFilters() { return { ...initialState } diff --git a/frontend/src/domain/use_cases/missions/filters/isMissionPartOfSelectedControlPlans.ts b/frontend/src/domain/use_cases/missions/filters/isMissionPartOfSelectedControlPlans.ts new file mode 100644 index 0000000000..a3a2f5f0c3 --- /dev/null +++ b/frontend/src/domain/use_cases/missions/filters/isMissionPartOfSelectedControlPlans.ts @@ -0,0 +1,16 @@ +import type { Mission } from '../../../entities/missions' + +export function isMissionPartOfSelectedControlPlans(mission: Mission, selectedThemes: number[] | undefined) { + if (!selectedThemes || selectedThemes.length === 0) { + return true + } + if (mission.envActions.length === 0) { + return false + } + + const missionControlPlans = mission.envActions.flatMap((action: any) => + action.controlPlans?.flatMap(controlPlan => controlPlan.themeId) + ) + + return missionControlPlans.some(controlPlan => selectedThemes.includes(controlPlan)) +} diff --git a/frontend/src/domain/use_cases/missions/filters/isMissionPartOfSelectedThemes.ts b/frontend/src/domain/use_cases/missions/filters/isMissionPartOfSelectedThemes.ts deleted file mode 100644 index 0ae7ba33de..0000000000 --- a/frontend/src/domain/use_cases/missions/filters/isMissionPartOfSelectedThemes.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Mission } from '../../../entities/missions' - -export function isMissionPartOfSelectedThemes(mission: Mission, selectedThemes: string[] | undefined) { - if (!selectedThemes || selectedThemes.length === 0) { - return true - } - if (mission.envActions.length === 0) { - return false - } - - const missionThemes = mission.envActions.flatMap((action: any) => action.themes?.flatMap(theme => theme.theme)) - const themesFiltered = missionThemes.filter(theme => selectedThemes.includes(theme)) - - return themesFiltered.length > 0 -} diff --git a/frontend/src/domain/use_cases/missions/saveMission.ts b/frontend/src/domain/use_cases/missions/saveMission.ts index 91143cf590..a1f67301b1 100644 --- a/frontend/src/domain/use_cases/missions/saveMission.ts +++ b/frontend/src/domain/use_cases/missions/saveMission.ts @@ -54,7 +54,7 @@ export const saveMission = reportings }) } else { - if (response.error.data.type === ApiErrorCode.CHILD_ALREADY_ATTACHED) { + if (response.error?.data?.type === ApiErrorCode.CHILD_ALREADY_ATTACHED) { throw Error('Le signalement est déjà rattaché à une mission') } throw Error('Erreur à la création ou à la modification de la mission') diff --git a/frontend/src/domain/use_cases/reporting/filters/subThemesFilterFunction.ts b/frontend/src/domain/use_cases/reporting/filters/subThemesFilterFunction.ts index 21e8386168..bb618b210a 100644 --- a/frontend/src/domain/use_cases/reporting/filters/subThemesFilterFunction.ts +++ b/frontend/src/domain/use_cases/reporting/filters/subThemesFilterFunction.ts @@ -1,13 +1,13 @@ import type { ReportingDetailed } from '../../../entities/reporting' -export function subThemesFilterFunction(reporting: ReportingDetailed, subThemesFilter: string[] | undefined) { +export function subThemesFilterFunction(reporting: ReportingDetailed, subThemesFilter: number[] | undefined) { if (!subThemesFilter || subThemesFilter.length === 0) { return true } - return !!reporting?.subThemes?.find(subTheme => { - if (subThemesFilter.find(subThemeFilter => subThemeFilter === subTheme)) { - return subTheme + return !!reporting?.subThemeIds?.find(subThemeId => { + if (subThemesFilter.find(subThemeFilter => subThemeFilter === subThemeId)) { + return subThemeId } return false diff --git a/frontend/src/domain/use_cases/reporting/filters/themeFilterFunction.ts b/frontend/src/domain/use_cases/reporting/filters/themeFilterFunction.ts index 09e0cb7905..1bd555a31f 100644 --- a/frontend/src/domain/use_cases/reporting/filters/themeFilterFunction.ts +++ b/frontend/src/domain/use_cases/reporting/filters/themeFilterFunction.ts @@ -1,9 +1,9 @@ import type { ReportingDetailed } from '../../../entities/reporting' -export function themeFilterFunction(reporting: ReportingDetailed, themeFilter: string[] | undefined) { +export function themeFilterFunction(reporting: ReportingDetailed, themeFilter: number[] | undefined) { if (!themeFilter || themeFilter.length === 0) { return true } - return !!reporting.theme && themeFilter.includes(reporting.theme) + return !!reporting.themeId && themeFilter.includes(reporting.themeId) } diff --git a/frontend/src/features/Reportings/Filters/Map/index.tsx b/frontend/src/features/Reportings/Filters/Map/index.tsx index d88d400b2a..5e9ee1f433 100644 --- a/frontend/src/features/Reportings/Filters/Map/index.tsx +++ b/frontend/src/features/Reportings/Filters/Map/index.tsx @@ -6,6 +6,7 @@ import { ReportingSourceLabels } from '../../../../domain/entities/reporting' import { ReportingsFiltersEnum, reportingsFiltersActions } from '../../../../domain/shared_slices/ReportingsFilters' import { useAppDispatch } from '../../../../hooks/useAppDispatch' import { useAppSelector } from '../../../../hooks/useAppSelector' +import { useGetControlPlans } from '../../../../hooks/useGetControlPlans' import { OptionValue, StyledSelect, StyledStatusFilter } from '../style' export function MapReportingsFiltersWithRef( @@ -31,15 +32,9 @@ export function MapReportingsFiltersWithRef( themeFilter, typeFilter } = useAppSelector(state => state.reportingFilters) - - const { - dateRangeOptions, - sourceTypeOptions, - statusOptions, - subThemesListAsOptions, - themesListAsOptions, - typeOptions - } = optionsList + const { subThemes, themes } = useGetControlPlans() + const { dateRangeOptions, sourceTypeOptions, statusOptions, subThemesOptions, themesOptions, typeOptions } = + optionsList const onDeleteTag = (valueToDelete: string | any, filterKey: ReportingsFiltersEnum, reportingFilter) => { const updatedFilter = reportingFilter.filter(unit => unit !== valueToDelete) @@ -143,7 +138,7 @@ export function MapReportingsFiltersWithRef( label="Thématiques" name="themes" onChange={value => updateSimpleFilter(value, ReportingsFiltersEnum.THEME_FILTER)} - options={themesListAsOptions} + options={themesOptions} placeholder="Thématiques" renderValue={() => themeFilter && {`Thème (${themeFilter.length})`}} searchable @@ -152,14 +147,14 @@ export function MapReportingsFiltersWithRef( {themeFilter && themeFilter.length > 0 && ( - {themeFilter.map(theme => ( + {themeFilter.map(themeId => ( onDeleteTag(theme, ReportingsFiltersEnum.THEME_FILTER, themeFilter)} - title={String(theme)} + onDelete={() => onDeleteTag(themeId, ReportingsFiltersEnum.THEME_FILTER, themeFilter)} + title={themes[themeId]?.theme} > - {String(theme)} + {String(themes[themeId]?.theme)} ))} @@ -170,7 +165,7 @@ export function MapReportingsFiltersWithRef( label="Sous-thématiques" name="subThemes" onChange={value => updateSimpleFilter(value, ReportingsFiltersEnum.SUB_THEMES_FILTER)} - options={subThemesListAsOptions} + options={subThemesOptions} placeholder="Sous-thématiques" renderValue={() => subThemesFilter && {`Sous-thème (${subThemesFilter.length})`}} searchable @@ -179,14 +174,14 @@ export function MapReportingsFiltersWithRef( {subThemesFilter && subThemesFilter.length > 0 && ( - {subThemesFilter.map(subTheme => ( + {subThemesFilter.map(subThemeId => ( onDeleteTag(subTheme, ReportingsFiltersEnum.SUB_THEMES_FILTER, subThemesFilter)} - title={String(subTheme)} + onDelete={() => onDeleteTag(subThemeId, ReportingsFiltersEnum.SUB_THEMES_FILTER, subThemesFilter)} + title={subThemes[subThemeId]?.subTheme} > - {String(subTheme)} + {String(subThemes[subThemeId]?.subTheme)} ))} diff --git a/frontend/src/features/Reportings/Filters/Table/FilterTags.tsx b/frontend/src/features/Reportings/Filters/Table/FilterTags.tsx index 1df24f1ca8..b3332b797b 100644 --- a/frontend/src/features/Reportings/Filters/Table/FilterTags.tsx +++ b/frontend/src/features/Reportings/Filters/Table/FilterTags.tsx @@ -5,8 +5,10 @@ import { ReportingSourceLabels } from '../../../../domain/entities/reporting' import { ReportingsFiltersEnum, reportingsFiltersActions } from '../../../../domain/shared_slices/ReportingsFilters' import { useAppDispatch } from '../../../../hooks/useAppDispatch' import { useAppSelector } from '../../../../hooks/useAppSelector' +import { useGetControlPlans } from '../../../../hooks/useGetControlPlans' export function FilterTags() { + const { subThemes, themes } = useGetControlPlans() const dispatch = useAppDispatch() const { hasFilters, seaFrontFilter, sourceFilter, sourceTypeFilter, subThemesFilter, themeFilter } = useAppSelector( state => state.reportingFilters @@ -52,24 +54,24 @@ export function FilterTags() { ))} {themeFilter && themeFilter.length > 0 && - themeFilter.map(theme => ( + themeFilter.map(themeId => ( onDeleteTag(theme, ReportingsFiltersEnum.THEME_FILTER, themeFilter)} + onDelete={() => onDeleteTag(themeId, ReportingsFiltersEnum.THEME_FILTER, themeFilter)} > - {String(`Thème ${theme}`)} + {String(`Thème ${themes[themeId]?.theme}`)} ))} {subThemesFilter && subThemesFilter?.length > 0 && - subThemesFilter.map(subTheme => ( + subThemesFilter.map(subThemeId => ( onDeleteTag(subTheme, ReportingsFiltersEnum.SUB_THEMES_FILTER, subThemesFilter)} + onDelete={() => onDeleteTag(subThemeId, ReportingsFiltersEnum.SUB_THEMES_FILTER, subThemesFilter)} > - {String(`Sous-thème ${subTheme}`)} + {String(`Sous-thème ${subThemes[subThemeId]?.subTheme}`)} ))} {seaFrontFilter && @@ -92,4 +94,5 @@ const StyledContainer = styled.div` flex-direction: row; gap: 16px; margin-bottom: 2px; + flex-wrap: wrap; ` diff --git a/frontend/src/features/Reportings/Filters/Table/index.tsx b/frontend/src/features/Reportings/Filters/Table/index.tsx index f7e72be283..cb236d1ff7 100644 --- a/frontend/src/features/Reportings/Filters/Table/index.tsx +++ b/frontend/src/features/Reportings/Filters/Table/index.tsx @@ -31,7 +31,8 @@ export function TableReportingsFiltersWithRef( updateDateRangeFilter, updatePeriodFilter, updateSimpleFilter, - updateSourceTypeFilter + updateSourceTypeFilter, + updateThemeFilter }, ref ) { @@ -56,14 +57,14 @@ export function TableReportingsFiltersWithRef( sourceOptions, sourceTypeOptions, statusOptions, - subThemesListAsOptions, - themesListAsOptions, + subThemesOptions, + themesOptions, typeOptions } = optionsList const sourceCustomSearch = useMemo( () => - new CustomSearch(sourceOptions as Option[], ['label'], { + new CustomSearch(sourceOptions as Array