Skip to content

Commit

Permalink
JPE - Ajout du message "Capture d'espèces protégées" (CPS) (#2768)
Browse files Browse the repository at this point in the history
## Linked issues

- Resolve #2765.
- Resolve #2769

----
- [x] Pipeline : mise à jour du parser ERS
- [x] Back et front : affichage des données de type `log_type=CPS`
- [ ] Rajouter nom entier de l'engin dans le payload de réponse API
  • Loading branch information
louptheron authored Feb 14, 2024
2 parents 531a743 + 7763a19 commit f6f8344
Show file tree
Hide file tree
Showing 100 changed files with 3,400 additions and 3,309 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package fr.gouv.cnsp.monitorfish.config

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.jsontype.NamedType
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import fr.gouv.cnsp.monitorfish.domain.entities.alerts.type.AlertTypeMapping
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.Catch
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.ProtectedSpeciesCatch
import fr.gouv.cnsp.monitorfish.domain.entities.reporting.ReportingTypeMapping
import fr.gouv.cnsp.monitorfish.domain.entities.rules.type.RuleTypeMapping
import org.springframework.context.annotation.Bean
Expand All @@ -27,9 +28,10 @@ class MapperConfiguration {
// needed to handle java.time.ZonedDateTime serialization
mapper.registerModule(JavaTimeModule())
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
mapper.propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE
mapper.propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE

mapper.registerSubtypes(NamedType(Catch::class.java, "catch"))
mapper.registerSubtypes(NamedType(ProtectedSpeciesCatch::class.java, "protectedSpeciesCatch"))
mapper.registerSubtypes(NamedType(GearLogbook::class.java, "gear"))

registerRulesSubType(mapper, RuleTypeMapping::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Haul() {
var mesh: Double? = null
var latitude: Double? = null
var longitude: Double? = null
var dimensions: String? = null

@JsonProperty("farDatetimeUtc")
var catchDateTime: ZonedDateTime? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package fr.gouv.cnsp.monitorfish.domain.entities.logbook
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.LogbookMessageValue
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.COE as COEMessage
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.COX as COXMessage
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.CPS as CPSMessage
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.CRO as CROMessage
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.DEP as DEPMessage
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.DIS as DISMessage
Expand All @@ -15,6 +16,7 @@ import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.RTP as RTPMessa

enum class LogbookMessageTypeMapping(private val clazz: Class<out LogbookMessageValue>) : IHasImplementation {
FAR(FARMessage::class.java),
CPS(CPSMessage::class.java),
DEP(DEPMessage::class.java),
DIS(DISMessage::class.java),
COX(COXMessage::class.java),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fr.gouv.cnsp.monitorfish.domain.entities.logbook

import com.fasterxml.jackson.annotation.JsonTypeName

@JsonTypeName("protectedSpeciesCatch")
class ProtectedSpeciesCatch {
lateinit var species: String
var speciesName: String? = null
var sex: String? = null
var healthState: HealthState? = null
var careMinutes: Int? = null
var ring: Int? = null
var fate: Fate? = null
var comment: String? = null
var weight: Double? = null
var nbFish: Double? = null
var faoZone: String? = null
var economicZone: String? = null
var statisticalRectangle: String? = null
var effortZone: String? = null
}

enum class HealthState {
DEA,
ALI,
INJ,
}

enum class Fate {
DIS,
HEC,
DEA,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages

import com.fasterxml.jackson.annotation.JsonProperty
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.ProtectedSpeciesCatch
import java.time.ZonedDateTime

class CPS : LogbookMessageValue {
@JsonProperty("cpsDatetimeUtc")
var cpsDatetime: ZonedDateTime? = null
var latitude: Double? = null
var longitude: Double? = null
var gear: String? = null
var mesh: Double? = null
var dimensions: String? = null
var catches: List<ProtectedSpeciesCatch> = listOf()
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.springframework.stereotype.Component

@Component
object ERSMapper {
private const val jsonbNullString = "null"
private const val JSONB_NULL_STRING = "null"

fun getERSMessageValueFromJSON(
mapper: ObjectMapper,
Expand All @@ -19,11 +19,11 @@ object ERSMapper {
operationType: LogbookOperationType,
): LogbookMessageValue? {
return try {
if (operationType == LogbookOperationType.RET && !message.isNullOrEmpty() && message != jsonbNullString) {
if (operationType == LogbookOperationType.RET && !message.isNullOrEmpty() && message != JSONB_NULL_STRING) {
val classType = LogbookOperationTypeMapping.getClassFromName(operationType.name)

mapper.readValue(message, classType)
} else if (!messageType.isNullOrEmpty() && !message.isNullOrEmpty() && message != jsonbNullString) {
} else if (!messageType.isNullOrEmpty() && !message.isNullOrEmpty() && message != JSONB_NULL_STRING) {
val classType = LogbookMessageTypeMapping.getClassFromName(messageType)

mapper.readValue(message, classType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class GetLogbookMessages(
LogbookMessageTypeMapping.FAR.name -> {
setNamesFromCodes(it.message as FAR)
}
LogbookMessageTypeMapping.CPS.name -> {
setNamesFromCodes(it.message as CPS)
}
LogbookMessageTypeMapping.DEP.name -> {
setNamesFromCodes(it.message as DEP)
}
Expand Down Expand Up @@ -231,6 +234,12 @@ class GetLogbookMessages(
}
}

private fun setNamesFromCodes(message: CPS) {
message.catches.forEach { catch ->
addSpeciesName(catch, catch.species)
}
}

private fun setNamesFromCodes(message: DEP) {
message.gearOnboard.forEach { gear ->
gear.gear?.let { gearCode ->
Expand Down Expand Up @@ -317,6 +326,14 @@ class GetLogbookMessages(
}
}

private fun addSpeciesName(catch: ProtectedSpeciesCatch, species: String) {
try {
catch.speciesName = speciesRepository.find(species).name
} catch (e: CodeNotFoundException) {
logger.warn(e.message)
}
}

private fun addGearName(gear: Gear, gearCode: String) {
try {
gear.gearName = gearRepository.find(gearCode).name
Expand Down
18 changes: 15 additions & 3 deletions backend/src/main/resources/db/testdata/V666.5__Insert_logbook.sql
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ VALUES ('OOF20190126059903', '<ers:OPS AD="FRA" FR="OOE" ON="OOF20190126059903"
('OOF20191030056523', ''),
('OOF20190126036598', ''),
('OOF20103048326985', ''),
('OOF20103048323658', ''),
('cc7ee632-e515-460f-a1c1-f82222a6d419', '<Flux>Message FLUX xml</Flux>'),
('a3c52754-97e1-4a21-ba2e-d8f16f4544e9', '<Flux>Message FLUX xml</Flux>'),
('d5c3b039-aaee-4cca-bcae-637fa8effe14', '<Flux>Message FLUX xml</Flux>'),
Expand Down Expand Up @@ -407,7 +408,7 @@ VALUES ('OOF20190265896325', 9463701, 'OOF', '2018-02-17T01:05:00Z', 'DAT', 'OOF
('OOF20191030059902', 9463715, 'OOF', '2019-10-17T11:32:00Z', 'DAT', 'OOF20191030059902', null,
'2019-10-30T11:32:00Z',
'FAK000999999', 'CALLME', 'DONTSINK', 'PHENOMENE', 'FRA', null, 'FAR',
'{"hauls": [{"gear": "GTN", "mesh": 100.0, "catches": [{"weight": 1500.0, "conversionFactor": 1.2, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 86.0, "nbFish": null, "conversionFactor": 1.0, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 2.0, "nbFish": null, "species": "SOL", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "RJH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}], "farDatetimeUtc": "2019-10-17T11:32:00Z"}]}',
'{"hauls": [{"gear": "GTN", "mesh": 100.0, "dimensions": "150.0;120.0", "catches": [{"weight": 1500.0, "conversionFactor": 1.2, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 86.0, "nbFish": null, "conversionFactor": 1.0, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 2.0, "nbFish": null, "species": "SOL", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "RJH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}], "farDatetimeUtc": "2019-10-17T11:32:00Z"}]}',
'2021-01-18T07:17:27.384921Z', 'ERS', 'TurboCatch (3.7-1)'),
('OOF20103048326985', null, 'OOF', '2019-10-17T11:36:00Z', 'RET', 'OOF20103048326985', 'OOF20191030059902',
'2019-10-30T11:32:00Z',
Expand All @@ -416,7 +417,14 @@ VALUES ('OOF20190265896325', 9463701, 'OOF', '2018-02-17T01:05:00Z', 'DAT', 'OOF
('OOF20191030059903', 9463715, 'OOF', '2019-10-17T11:36:00Z', 'COR', 'OOF20191030059903', 'OOF20191030059902',
'2019-10-30T11:32:00Z',
'FAK000999999', 'CALLME', 'DONTSINK', 'PHENOMENE', 'FRA', null, 'FAR',
'{"hauls": [{"gear": "GTN", "mesh": 150.0, "catches": [{"weight": 1500.0, "conversionFactor": 1.0, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "presentation": "GUT", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 256.0, "conversionFactor": 1.0, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "presentation": "OTH", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 86.0, "nbFish": null, "conversionFactor": 1.0, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 2.0, "nbFish": null, "species": "SOL", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "RJH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "LAO", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "GPE", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "EOD", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "BGP", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "RPD", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "TYU", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "BVC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 57.0, "nbFish": null, "species": "EDC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 7.0, "nbFish": null, "species": "RGH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 47.0, "nbFish": null, "species": "EGT", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "TYU", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "BVC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "EDC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "RGH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "EGT", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}], "farDatetimeUtc": "2019-10-17T11:32:00Z"}]}',
-- As a result of a change in the ers parser in december 2023, the `dimensions` field holds numeric data as well as string data.
-- Before the change, the parser casted the `dimensions` field extracted from xml files to float
-- But this field can contain strings that cannot be casted to float, like "150.0;120.0" for gears with multiple dimensions.
-- This resulted in `null` values for the dimensions field when the value could not be casted, and the information was lost.
-- In december 2023, the type casting was removed from the parser and the dimensions field became a string, but the data already in the database
-- prior to the change was not updated and therefore still contains some floats. So it is important to keep both strings and floats in test data
-- in the `dimensions` field in order to ensure the app can handle both.
'{"hauls": [{"gear": "GTN", "mesh": 150.0, "dimensions": 120.0, "catches": [{"weight": 1500.0, "conversionFactor": 1.0, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "presentation": "GUT", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 256.0, "conversionFactor": 1.0, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "presentation": "OTH", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 86.0, "nbFish": null, "conversionFactor": 1.0, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 2.0, "nbFish": null, "species": "SOL", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "RJH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "LAO", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "GPE", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "EOD", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "BGP", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "RPD", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "TYU", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "BVC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 57.0, "nbFish": null, "species": "EDC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 7.0, "nbFish": null, "species": "RGH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 47.0, "nbFish": null, "species": "EGT", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "TYU", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "BVC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 17.0, "nbFish": null, "species": "EDC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "RGH", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 37.0, "nbFish": null, "species": "EGT", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}], "farDatetimeUtc": "2019-10-17T11:32:00Z"}]}',
'2021-01-18T07:19:27.384921Z', 'ERS', 'e-Sacapt Secours ERSV3 V 1.0.7'),
('OOF20191030056523', 9463715, 'OOF', '2019-10-17T11:37:00Z', 'DAT', 'OOF20191030056523', 'OOF20191030056523',
'2019-10-30T11:37:00Z',
Expand Down Expand Up @@ -462,7 +470,11 @@ VALUES ('OOF20190265896325', 9463701, 'OOF', '2018-02-17T01:05:00Z', 'DAT', 'OOF
'2019-06-27T11:06:00Z',
'FAK000999999', 'CALLME', 'DONTSINK', 'PHENOMENE', 'FRA', null, 'LAN',
'{"port": "AEAJM", "sender": "MAS", "catchLanded": [{"weight": 10.0, "conversionFactor": 1.2, "nbFish": null, "species": "SLS", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 20.0, "conversionFactor": 1.0, "nbFish": null, "species": "SLS", "faoZone": "27.8.b", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 180.0, "nbFish": null, "species": "HKC", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 1500.0, "nbFish": null, "species": "BON", "faoZone": "27.8.a", "effortZone": "C", "economicZone": "FRA", "statisticalRectangle": "23E6"}, {"weight": 200.0, "nbFish": null, "species": "SCR", "faoZone": "27.8.a", "freshness": null, "packaging": "CNT", "effortZone": "C", "presentation": "WHL", "economicZone": "FRA", "preservationState": "ALI", "statisticalRectangle": "24E6"}, {"weight": 6.0, "nbFish": null, "species": "LBE", "faoZone": "27.8.a", "freshness": null, "packaging": "CNT", "effortZone": "C", "presentation": "WHL", "economicZone": "FRA", "preservationState": "ALI", "statisticalRectangle": "24E6"}], "landingDatetimeUtc": "2019-10-22T11:06:00Z"}',
'2021-01-18T07:17:28.2717Z', 'ERS', 'TurboCatch (3.7-1)'),
'2021-01-18T09:17:28.2717Z', 'ERS', 'TurboCatch (3.7-1)'),
('OOF20103048323658', 9463715, 'OOF', '2019-10-11T01:06:00Z', 'DAT', 'OOF20103048323658', null,
'2019-10-11T01:06:00Z', 'FAK000999999', 'CALLME', 'DONTSINK', 'PHENOMENE', 'FRA', null, 'CPS',
'{"cpsDatetimeUtc": "2023-02-28T17:44:00Z","gear": "GTR","mesh": 100.0,"dimensions": "50.0;2.0","catches": [{"sex": "M","healthState": "DEA","careMinutes": null,"ring": "1234567","fate": "DIS","comment": null,"species": "DCO","weight": 60.0,"nbFish": 1.0,"faoZone": "27.8.a","economicZone": "FRA","statisticalRectangle": "22E7","effortZone": "C"},{"sex": "M","healthState": "DEA","careMinutes": 40,"ring": "1234568","fate": "DIS","comment": "A comment","species": "DCO","weight": 80.0,"nbFish": 1.0,"faoZone": "27.8.a","economicZone": "FRA","statisticalRectangle": "22E7","effortZone": "C"}],"latitude": 46.575,"longitude": -2.741}',
'2019-10-11T01:17:28.2717Z', 'ERS', 'TurboCatch (3.7-1)'),
('OOF22103048321399', null, 'OOF', '2019-10-17T11:36:00Z', 'RET', null, 'OOF20190627059908',
'2019-10-30T11:32:00Z',
null, null, null, null, null, null, '',
Expand Down
Loading

0 comments on commit f6f8344

Please sign in to comment.