From 9982dd02f5275b50856483b9aa003da0ba7b9047 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 14 Aug 2024 15:24:45 +0200 Subject: [PATCH 01/26] Flag acknowledged prior notifications in pno list query --- .../interfaces/DBLogbookReportRepository.kt | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index a61a713910..cf1fe5ae7a 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -136,16 +136,9 @@ interface DBLogbookReportRepository : AND lr.operation_type = 'DEL' ), - ret_pno_logbook_reports AS ( - SELECT - lr.*, - CAST(NULL AS TEXT[]) AS prior_notification_type_names, - CAST(NULL AS TEXT[]) AS specy_codes, - CAST(NULL AS TEXT[]) AS trip_gear_codes, - CAST(NULL AS TEXT[]) AS trip_segment_codes, - CAST(NULL AS INTEGER) AS reporting_count + acknowledged_report_ids AS ( + SELECT DISTINCT referenced_report_id FROM logbook_reports lr - JOIN filtered_dat_and_cor_pno_logbook_reports fdacplr ON lr.referenced_report_id = fdacplr.report_id WHERE -- This filter helps Timescale optimize the query since `operation_datetime_utc` is indexed lr.operation_datetime_utc @@ -153,20 +146,22 @@ interface DBLogbookReportRepository : AND CAST(:willArriveBefore AS TIMESTAMP) + INTERVAL '48 hours' AND lr.operation_type = 'RET' + AND lr.value->>'returnStatus' = '000' ) SELECT * FROM filtered_dat_and_cor_pno_logbook_reports + WHERE + report_id IN (SELECT referenced_report_id FROM acknowledged_report_ids) + OR transmission_format = 'FLUX' - UNION + UNION ALL SELECT * FROM del_pno_logbook_reports - - UNION - - SELECT * - FROM ret_pno_logbook_reports; + WHERE + operation_number IN (SELECT referenced_report_id FROM acknowledged_report_ids) + OR transmission_format = 'FLUX' """, nativeQuery = true, ) From 2ec872bee0dfe55a5f692938faa128d1f3706ca4 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 14 Aug 2024 17:18:07 +0200 Subject: [PATCH 02/26] Update get logbook pno by report_id query --- .../interfaces/DBLogbookReportRepository.kt | 88 +++++++++---------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index cf1fe5ae7a..4125015319 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -184,83 +184,81 @@ interface DBLogbookReportRepository : @Query( """ WITH - dats_cors AS ( - -- Get the logbook report reference (DAT operation) - -- It may not exist while a COR operation would still exist (orphan COR case) + searched_pno AS ( SELECT * FROM logbook_reports WHERE - -- This filter helps Timescale optimize the query since `operation_datetime_utc` is indexed operation_datetime_utc - BETWEEN CAST(:operationDate AS TIMESTAMP) - INTERVAL '48 hours' - AND CAST(:operationDate AS TIMESTAMP) + INTERVAL '48 hours' - + BETWEEN CAST(:operationDate AS TIMESTAMP) - INTERVAL '4 hours' + AND CAST(:operationDate AS TIMESTAMP) + INTERVAL '4 hours' AND report_id = :reportId AND log_type = 'PNO' - AND operation_type = 'DAT' AND enriched = TRUE + ), - UNION ALL + dels_targeting_searched_pno AS ( - -- Get the logbook report corrections which may be used as base for the "final" report - SELECT * - FROM logbook_reports - WHERE - -- This filter helps Timescale optimize the query since `operation_datetime_utc` is indexed - operation_datetime_utc - BETWEEN CAST(:operationDate AS TIMESTAMP) - INTERVAL '48 hours' - AND CAST(:operationDate AS TIMESTAMP) + INTERVAL '48 hours' - - AND referenced_report_id = :reportId - AND log_type = 'PNO' - AND operation_type = 'COR' - AND enriched = TRUE + -- A DEL message has no flag_state, which we need to acknowledge messages of non french vessels. + -- So we use the flag_state of the deleted message. + SELECT del.referenced_report_id, del.operation_number, searched_pno.flag_state + FROM logbook_reports del + JOIN searched_pno + ON del.referenced_report_id = searched_pno.report_id + WHERE + del.operation_datetime_utc + BETWEEN CAST(:operationDate AS TIMESTAMP) - INTERVAL '48 hours' + AND CAST(:operationDate AS TIMESTAMP) + INTERVAL '48 hours' + AND del.operation_type = 'DEL' ), - dels AS ( + cors_targeting_searched_pno AS ( SELECT * FROM logbook_reports WHERE - -- This filter helps Timescale optimize the query since `operation_datetime_utc` is indexed operation_datetime_utc BETWEEN CAST(:operationDate AS TIMESTAMP) - INTERVAL '48 hours' AND CAST(:operationDate AS TIMESTAMP) + INTERVAL '48 hours' - - AND operation_type = 'DEL' - AND referenced_report_id IN (SELECT report_id FROM dats_cors) + AND operation_type = 'COR' + AND referenced_report_id = :reportId ), - rets AS ( - SELECT * + acknowledged_cors_and_dels AS ( + SELECT DISTINCT referenced_report_id FROM logbook_reports WHERE - -- This filter helps Timescale optimize the query since `operation_datetime_utc` is indexed operation_datetime_utc BETWEEN CAST(:operationDate AS TIMESTAMP) - INTERVAL '48 hours' AND CAST(:operationDate AS TIMESTAMP) + INTERVAL '48 hours' - AND operation_type = 'RET' + AND value->>'returnStatus' = '000' AND referenced_report_id IN ( - SELECT report_id FROM dats_cors + SELECT operation_number FROM dels_targeting_searched_pno UNION ALL - SELECT report_id FROM dels + SELECT report_id FROM cors_targeting_searched_pno ) - ) - - SELECT * - FROM dats_cors - - UNION ALL + ), - SELECT * - FROM dels + acknowledged_dels_targeting_searched_pno AS ( + SELECT referenced_report_id + FROM dels_targeting_searched_pno + WHERE + operation_number IN (SELECT referenced_report_id FROM acknowledged_cors_and_dels) + OR flag_state NOT IN ('FRA', 'GUF', 'VEN') -- flag_states for which we received RET messages + ), - UNION ALL + acknowledged_cors_targeting_searched_pno AS ( + SELECT referenced_report_id + FROM cors_targeting_searched_pno + WHERE + report_id IN (SELECT referenced_report_id FROM acknowledged_cors_and_dels) + OR flag_state NOT IN ('FRA', 'GUF', 'VEN') -- flag_states for which we received RET messages + ) SELECT * - FROM rets - - ORDER BY report_datetime_utc; + FROM searched_pno + WHERE + report_id NOT IN (SELECT referenced_report_id FROM acknowledged_dels_targeting_searched_pno) AND + report_id NOT IN (SELECT referenced_report_id FROM acknowledged_cors_targeting_searched_pno) """, nativeQuery = true, ) From 4e9924b0ad62b168fd88acbcabff7ab72da7c6a1 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 14 Aug 2024 17:21:47 +0200 Subject: [PATCH 03/26] Update query --- .../repositories/interfaces/DBLogbookReportRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index 4125015319..392fcfa7bb 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -153,7 +153,7 @@ interface DBLogbookReportRepository : FROM filtered_dat_and_cor_pno_logbook_reports WHERE report_id IN (SELECT referenced_report_id FROM acknowledged_report_ids) - OR transmission_format = 'FLUX' + OR flag_state NOT IN ('FRA', 'GUF', 'VEN') -- flag_states for which we received RET messages UNION ALL @@ -161,7 +161,7 @@ interface DBLogbookReportRepository : FROM del_pno_logbook_reports WHERE operation_number IN (SELECT referenced_report_id FROM acknowledged_report_ids) - OR transmission_format = 'FLUX' + OR flag_state NOT IN ('FRA', 'GUF', 'VEN') -- flag_states for which we received RET messages """, nativeQuery = true, ) From f8e3c610abfd4cd2330e9326df3bec948e62393b Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Wed, 14 Aug 2024 16:17:11 +0200 Subject: [PATCH 04/26] Remove logbook prior notification consolidation in Backend --- .../domain/entities/logbook/LogbookMessage.kt | 16 +- .../repositories/LogbookReportRepository.kt | 2 +- .../database/entities/LogbookReportEntity.kt | 10 +- .../JpaLogbookReportRepository.kt | 219 ++++----- .../interfaces/DBLogbookReportRepository.kt | 4 +- .../entities/logbook/LogbookMessageUTests.kt | 427 ------------------ .../JpaLogbookReportRepositoryITests.kt | 91 ---- 7 files changed, 89 insertions(+), 680 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt index a3888b1eb0..e95c32ee7c 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt @@ -52,7 +52,6 @@ data class LogbookMessage( } fun toConsolidatedLogbookMessageAndValue( - relatedLogbookMessages: List, clazz: Class, ): LogbookMessageAndValue { if (reportId == null) { @@ -66,19 +65,12 @@ data class LogbookMessage( ) } - val historicallySortedRelatedLogbookMessages = relatedLogbookMessages.sortedBy { it.reportDateTime } - val maybeLastLogbookMessageCorrection = historicallySortedRelatedLogbookMessages - .lastOrNull { it.operationType == LogbookOperationType.COR } - - val logbookMessageBase = maybeLastLogbookMessageCorrection ?: this - logbookMessageBase.enrichAcnkowledge(relatedLogbookMessages) - val finalLogbookMessage = logbookMessageBase.copy( - isCorrectedByNewerMessage = false, - isDeleted = historicallySortedRelatedLogbookMessages.any { it.operationType == LogbookOperationType.DEL }, - ) + // val logbookMessageBase = this + // logbookMessageBase.enrichAcnkowledge(relatedLogbookMessages) + // logbookMessageBase.enrichAcnkowledge(relatedLogbookMessages) return LogbookMessageAndValue( - logbookMessage = finalLogbookMessage, + logbookMessage = this, clazz = clazz, ) } diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt index 8769073298..afc2477ec8 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt @@ -73,7 +73,7 @@ interface LogbookReportRepository { isBeingSent: Boolean, isSent: Boolean, isVerified: Boolean, - ) + ): PriorNotification fun findAllPriorNotificationsToVerify(): List diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt index 560043db78..9105d82224 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt @@ -140,14 +140,12 @@ data class LogbookReportEntity( ) } - fun toPriorNotification(mapper: ObjectMapper, relatedModels: List): PriorNotification { + fun toPriorNotification(mapper: ObjectMapper): PriorNotification { val referenceLogbookMessage = toLogbookMessage(mapper) - val relatedLogbookMessages = relatedModels - .map { it.toLogbookMessage(mapper) } - .sortedBy { it.operationDateTime } + val consolidatedLogbookMessageAndValue = referenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - val updatedAt = relatedLogbookMessages.lastOrNull()?.operationDateTime ?: operationDateTime.atZone(UTC) + .toConsolidatedLogbookMessageAndValue(PNO::class.java) + val updatedAt = operationDateTime.atZone(UTC) // For practical reasons `vessel` can't be `null`, so we temporarily set it to "Navire inconnu" val vessel = UNKNOWN_VESSEL diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 3469e22f79..7076e6ab0a 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -4,12 +4,14 @@ import com.fasterxml.jackson.databind.ObjectMapper import fr.gouv.cnsp.monitorfish.Utils import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessage import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessageAndValue -import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookOperationType import fr.gouv.cnsp.monitorfish.domain.entities.logbook.VoyageDatesAndTripNumber import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotification import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.filters.PriorNotificationsFilter -import fr.gouv.cnsp.monitorfish.domain.exceptions.* +import fr.gouv.cnsp.monitorfish.domain.exceptions.BackendUsageErrorCode +import fr.gouv.cnsp.monitorfish.domain.exceptions.BackendUsageException +import fr.gouv.cnsp.monitorfish.domain.exceptions.NoERSMessagesFound +import fr.gouv.cnsp.monitorfish.domain.exceptions.NoLogbookFishingTripFound import fr.gouv.cnsp.monitorfish.domain.repositories.LogbookReportRepository import fr.gouv.cnsp.monitorfish.infrastructure.database.entities.LogbookReportEntity import fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.interfaces.DBLogbookReportRepository @@ -34,7 +36,7 @@ class JpaLogbookReportRepository( private val logger = LoggerFactory.getLogger(JpaLogbookReportRepository::class.java) override fun findAllPriorNotifications(filter: PriorNotificationsFilter): List { - val allLogbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( + val logbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( flagStates = filter.flagStates ?: emptyList(), hasOneOrMoreReportings = filter.hasOneOrMoreReportings, isLessThanTwelveMetersVessel = filter.isLessThanTwelveMetersVessel, @@ -50,24 +52,23 @@ class JpaLogbookReportRepository( willArriveBefore = filter.willArriveBefore, ) - return mapToReferenceWithRelatedModels(allLogbookReportModels) - .mapNotNull { (referenceLogbookReportModel, relatedLogbookReportModels) -> - try { - referenceLogbookReportModel.toPriorNotification(objectMapper, relatedLogbookReportModels) - } catch (e: Exception) { - logger.warn( - "Error while converting logbook report models to prior notifications (reportId = ${referenceLogbookReportModel.reportId}).", - e, - ) + return logbookReportModels.mapNotNull { logbookReportModel -> + try { + logbookReportModel.toPriorNotification(objectMapper) + } catch (e: Exception) { + logger.warn( + "Error while converting logbook report model to prior notification (reportId = ${logbookReportModel.reportId}).", + e, + ) - null - } + null } + } } @Cacheable(value = ["pno_to_verify"]) override fun findAllPriorNotificationsToVerify(): List { - val allLogbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( + val logbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( flagStates = emptyList(), hasOneOrMoreReportings = null, isLessThanTwelveMetersVessel = null, @@ -83,45 +84,31 @@ class JpaLogbookReportRepository( willArriveBefore = CustomZonedDateTime(ZonedDateTime.now().plusHours(24)).toString(), ) - return mapToReferenceWithRelatedModels(allLogbookReportModels) - .mapNotNull { (referenceLogbookReportModel, relatedLogbookReportModels) -> - try { - referenceLogbookReportModel.toPriorNotification(objectMapper, relatedLogbookReportModels) - } catch (e: Exception) { - logger.warn( - "Error while converting logbook report models to prior notifications (reportId = ${referenceLogbookReportModel.reportId}).", - e, - ) + return logbookReportModels.mapNotNull { referenceLogbookReportModel -> + try { + referenceLogbookReportModel.toPriorNotification(objectMapper) + } catch (e: Exception) { + logger.warn( + "Error while converting logbook report model to prior notifications (reportId = ${referenceLogbookReportModel.reportId}).", + e, + ) - null - } - }.filter { - it.logbookMessageAndValue.value.isInVerificationScope == true && - it.logbookMessageAndValue.value.isVerified == false && - it.logbookMessageAndValue.value.isInvalidated != true + null } + }.filter { + it.logbookMessageAndValue.value.isInVerificationScope == true && + it.logbookMessageAndValue.value.isVerified == false && + it.logbookMessageAndValue.value.isInvalidated != true + } } override fun findPriorNotificationByReportId(reportId: String, operationDate: ZonedDateTime): PriorNotification? { - val allLogbookReportModels = dbLogbookReportRepository.findEnrichedPnoReferenceAndRelatedOperationsByReportId( + val logbookReportModel = dbLogbookReportRepository.findByReportId( reportId, operationDate.toString(), ) - if (allLogbookReportModels.isEmpty()) { - return null - } - try { - val (referenceLogbookReportModel, relatedLogbookReportModels) = - mapToReferenceWithRelatedModels(allLogbookReportModels).first() - - return referenceLogbookReportModel.toPriorNotification(objectMapper, relatedLogbookReportModels) - } catch (e: Exception) { - throw EntityConversionException( - "Error while converting logbook report models to prior notification (reoportId = $reportId).", - e, - ) - } + return logbookReportModel?.toPriorNotification(objectMapper) } override fun findLastTripBeforeDateTime( @@ -354,7 +341,7 @@ class JpaLogbookReportRepository( override fun savePriorNotification(logbookMessageAndValue: LogbookMessageAndValue): PriorNotification { return dbLogbookReportRepository .save(LogbookReportEntity.fromLogbookMessage(objectMapper, logbookMessageAndValue.logbookMessage)) - .toPriorNotification(objectMapper, emptyList()) + .toPriorNotification(objectMapper) } @Transactional @@ -366,30 +353,25 @@ class JpaLogbookReportRepository( isBeingSent: Boolean, isSent: Boolean, isVerified: Boolean, - ) { - val logbookReportEntities = - dbLogbookReportRepository.findEnrichedPnoReferenceAndRelatedOperationsByReportId( + ): PriorNotification { + val logbookReportModel = + dbLogbookReportRepository.findByReportId( reportId, operationDate.withZoneSameInstant(UTC).toString(), ) - if (logbookReportEntities.isEmpty()) { + if (logbookReportModel == null) { throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) } - // We need to update both DAT and related COR operations (which also covers orphan COR cases) - logbookReportEntities - .filter { it.operationType in listOf(LogbookOperationType.DAT, LogbookOperationType.COR) } - .map { logbookReportEntity -> - val pnoMessage = objectMapper.readValue(logbookReportEntity.message, PNO::class.java) - pnoMessage.isBeingSent = isBeingSent - pnoMessage.isSent = isSent - pnoMessage.isVerified = isVerified + val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + pnoMessage.isBeingSent = isBeingSent + pnoMessage.isSent = isSent + pnoMessage.isVerified = isVerified - val nextMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedEntity = logbookReportEntity.copy(message = nextMessage) + val nextMessage = objectMapper.writeValueAsString(pnoMessage) + val updatedModel = logbookReportModel.copy(message = nextMessage) - dbLogbookReportRepository.save(updatedEntity) - } + return dbLogbookReportRepository.save(updatedModel).toPriorNotification(objectMapper) } @Transactional @@ -400,106 +382,61 @@ class JpaLogbookReportRepository( authorTrigram: String?, note: String?, ) { - val logbookReportEntities = - dbLogbookReportRepository.findEnrichedPnoReferenceAndRelatedOperationsByReportId( + val logbookReportModel = + dbLogbookReportRepository.findByReportId( reportId, operationDate.withZoneSameInstant(UTC).toString(), ) - if (logbookReportEntities.isEmpty()) { + if (logbookReportModel == null) { throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) } - // We need to update both DAT and related COR operations (which also covers orphan COR cases) - logbookReportEntities - .filter { it.operationType in listOf(LogbookOperationType.DAT, LogbookOperationType.COR) } - .map { logbookReportEntity -> - val pnoMessage = objectMapper.readValue(logbookReportEntity.message, PNO::class.java) - if ( - !Utils.areStringsEqual(authorTrigram, pnoMessage.authorTrigram) || - !Utils.areStringsEqual(note, pnoMessage.note) - ) { - pnoMessage.authorTrigram = authorTrigram - pnoMessage.note = note - - /** - * The PNO states are re-initialized: - * - the PDF will be re-generated (done in the use case by deleting the old one) - * - the PNO will require another verification before sending - */ - pnoMessage.isBeingSent = false - pnoMessage.isSent = false - pnoMessage.isVerified = false - - val nextMessage = objectMapper.writeValueAsString(pnoMessage) - - val updatedEntity = logbookReportEntity.copy(message = nextMessage) - - dbLogbookReportRepository.save(updatedEntity) - } - } + val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + if ( + Utils.areStringsEqual(authorTrigram, pnoMessage.authorTrigram) && + Utils.areStringsEqual(note, pnoMessage.note) + ) { + return + } + + pnoMessage.authorTrigram = authorTrigram + pnoMessage.note = note + /** + * The PNO states are re-initialized: + * - the PDF will be re-generated (done in the use case by deleting the old one) + * - the PNO will require another verification before sending + */ + pnoMessage.isBeingSent = false + pnoMessage.isSent = false + pnoMessage.isVerified = false + + val nextMessage = objectMapper.writeValueAsString(pnoMessage) + val updatedModel = logbookReportModel.copy(message = nextMessage) + + dbLogbookReportRepository.save(updatedModel) } @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val logbookReportEntities = - dbLogbookReportRepository.findEnrichedPnoReferenceAndRelatedOperationsByReportId( + val logbookReportModel = + dbLogbookReportRepository.findByReportId( reportId, operationDate.withZoneSameInstant(UTC).toString(), ) - if (logbookReportEntities.isEmpty()) { + if (logbookReportModel == null) { throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) } - // We need to update both DAT and related COR operations (which also covers orphan COR cases) - logbookReportEntities - .filter { it.operationType in listOf(LogbookOperationType.DAT, LogbookOperationType.COR) } - .map { logbookReportEntity -> - val pnoMessage = objectMapper.readValue(logbookReportEntity.message, PNO::class.java) - pnoMessage.isInvalidated = true - - val nextMessage = objectMapper.writeValueAsString(pnoMessage) + val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + pnoMessage.isInvalidated = true - val updatedEntity = logbookReportEntity.copy(message = nextMessage) + val nextMessage = objectMapper.writeValueAsString(pnoMessage) + val updatedEntity = logbookReportModel.copy(message = nextMessage) - dbLogbookReportRepository.save(updatedEntity) - } + dbLogbookReportRepository.save(updatedEntity) } private fun getAllMessagesExceptionMessage(internalReferenceNumber: String) = "No messages found for the vessel. (internalReferenceNumber: \"$internalReferenceNumber\")" - - companion object { - fun mapToReferenceWithRelatedModels( - allLogbookReportModels: List, - ): List>> { - // DAT operations are references by definition - val datLogbookReportModels = allLogbookReportModels.filter { it.operationType == LogbookOperationType.DAT } - // Orphan COR operations are also considered as references for lack of anything better - // They can be orphan for various reasons, like an error along the external JPE flow. - val orphanCorLogbookReportModels = allLogbookReportModels - .filter { it.operationType == LogbookOperationType.COR } - .filter { corOperation -> - corOperation.referencedReportId == null || - datLogbookReportModels.none { it.reportId == corOperation.referencedReportId } - } - val referenceLogbookReportModels = datLogbookReportModels + orphanCorLogbookReportModels - - return referenceLogbookReportModels.map { referenceLogbookReportModel -> - val directlyAssociatedLogbookReportModels = allLogbookReportModels.filter { - it.referencedReportId == referenceLogbookReportModel.reportId - } - // COR operation also have their own `reportId` which can also be associated to their own operations - // For example, a RET (aknlowledgement) operation can be associated to a COR operation. - val directlyAssociatedReportIds = directlyAssociatedLogbookReportModels.mapNotNull { it.reportId } - val indirectlyAssociatedLogbookReportModels = allLogbookReportModels.filter { - it.referencedReportId in directlyAssociatedReportIds - } - val associatedLogbookReportModels = directlyAssociatedLogbookReportModels + - indirectlyAssociatedLogbookReportModels - - Pair(referenceLogbookReportModel, associatedLogbookReportModels) - } - } - } } diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index 392fcfa7bb..ff788b1ed7 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -262,10 +262,10 @@ interface DBLogbookReportRepository : """, nativeQuery = true, ) - fun findEnrichedPnoReferenceAndRelatedOperationsByReportId( + fun findByReportId( reportId: String, operationDate: String, - ): List + ): LogbookReportEntity? @Query( """SELECT new fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.interfaces.VoyageTripNumberAndDate(e.tripNumber, MIN(e.operationDateTime)) diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessageUTests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessageUTests.kt index fb40961f83..bde3151b61 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessageUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessageUTests.kt @@ -2,7 +2,6 @@ package fr.gouv.cnsp.monitorfish.domain.entities.logbook import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.Acknowledgment import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.LogbookMessageValue -import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -39,432 +38,6 @@ class LogbookMessageUTests { } } - @Test - fun `toConsolidatedLogbookMessageAndValue Should set acknowledge to successful with one successful RET message`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "000"), - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isTrue() - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should set acknowledge to successful with multiple RET messages of which one is successful, no matter the (historical) order`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "002"), - ), - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "000"), - ), - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 3, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "001"), - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isTrue() - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should set acknowledge to not successful with one unsuccessful RET message`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "001"), - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should set acknowledge to (most recent) not successful with multiple unsucessful RET message`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "001"), - ), - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "002"), - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.dateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - - // When - val enrichedLogbookMessageReversed = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages.reversed(), PNO::class.java) - - // Then - assertThat(enrichedLogbookMessageReversed.logbookMessage.acknowledgment?.isSuccess).isFalse() - assertThat(enrichedLogbookMessageReversed.logbookMessage.acknowledgment?.dateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessageReversed.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessageReversed.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should set acknowledge to successful when it comes from FLUX flow`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ).copy( - transmissionFormat = LogbookTransmissionFormat.FLUX, - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(emptyList(), PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isTrue() - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should set acknowledge to successful when it was generated via VISIOCaptures app`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ).copy( - software = "... VISIOCaptures ...", - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(emptyList(), PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isTrue() - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should flag it as corrected from an orphan COR message`() { - // Given - val missingDatLogbookMessageReportId = UUID.randomUUID().toString() - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - missingDatLogbookMessageReportId, - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(emptyList(), PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should use the most recent COR message as base and flag it corrected from a DAT with multiple COR messages`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 3, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime).isEqualTo( - ZonedDateTime.of(2024, 1, 1, 0, 0, 3, 0, ZoneOffset.UTC), - ) - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - - // When - val enrichedLogbookMessageReversed = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages.reversed(), PNO::class.java) - - // Then - assertThat(enrichedLogbookMessageReversed.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 3, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessageReversed.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessageReversed.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should flag it as deleted from a DAT with a DEL message`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.DEL, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isTrue() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should flag it as corrected and deleted from an orphan COR with a DEL message`() { - // Given - val missingDatLogbookMessageReportId = UUID.randomUUID().toString() - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - missingDatLogbookMessageReportId, - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.DEL, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isTrue() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should use the most recent COR message as base and flag it corrected and deleted from a DAT with COR and DEL messages`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - getFakeLogbookMessage( - LogbookOperationType.DEL, - ZonedDateTime.of(2024, 1, 1, 0, 0, 3, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isTrue() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should use the most recent COR message as base and associate its RET from a DAT, even with a later DAT-RET message`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val corLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - // This first RET message is related to the DAT message. - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "000"), - ), - corLogbookMessage, - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 3, 0, ZoneOffset.UTC), - // This second RET message is related to the COR and not DAT message. - corLogbookMessage.reportId, - Acknowledgment(returnStatus = "002"), - ), - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 4, 0, ZoneOffset.UTC), - // This third RET message is related to the COR and not DAT message. - corLogbookMessage.reportId, - Acknowledgment(returnStatus = "001"), - ), - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 5, 0, ZoneOffset.UTC), - // This fourth RET message is related to the DAT message. - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "000"), - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.isSuccess).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.dateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 4, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment?.returnStatus).isEqualTo("001") - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - - @Test - fun `toConsolidatedLogbookMessageAndValue Should use the most recent COR message as base and skip acknowledgement flagging without a COR-related RET`() { - // Given - val refenceLogbookMessage = getFakeLogbookMessage( - LogbookOperationType.DAT, - ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), - ) - val relatedLogbookMessages = listOf( - getFakeLogbookMessage( - LogbookOperationType.RET, - ZonedDateTime.of(2024, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC), - // This first RET message is related to the DAT message. - refenceLogbookMessage.reportId, - Acknowledgment(returnStatus = "000"), - ), - getFakeLogbookMessage( - LogbookOperationType.COR, - ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC), - refenceLogbookMessage.reportId, - ), - ) - - // When - val enrichedLogbookMessage = refenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(relatedLogbookMessages, PNO::class.java) - - // Then - assertThat(enrichedLogbookMessage.logbookMessage.reportDateTime) - .isEqualTo(ZonedDateTime.of(2024, 1, 1, 0, 0, 2, 0, ZoneOffset.UTC)) - assertThat(enrichedLogbookMessage.logbookMessage.acknowledgment).isNull() - assertThat(enrichedLogbookMessage.logbookMessage.isCorrectedByNewerMessage).isFalse() - assertThat(enrichedLogbookMessage.logbookMessage.isDeleted).isFalse() - } - @Test fun `setAcknowledge should create a new successful acknowledgment when current is null`() { // Given diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt index 32bb1cc3bb..e462729541 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt @@ -1013,97 +1013,6 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { assertThat(result.messageType).isEqualTo("PNO") } - @Test - @Transactional - fun `mapToReferenceWithRelatedModels should correctly map models`() { - // Given - - val firstLogbookReportGroupDatOperation = getFakeLogbookReportModel(LogbookOperationType.DAT) - val firstLogbookReportGroup = listOf( - firstLogbookReportGroupDatOperation, - ) - - val secondLogbookReportGroupDatOperation = getFakeLogbookReportModel(LogbookOperationType.DAT) - val secondLogbookReportGroup = listOf( - secondLogbookReportGroupDatOperation, - getFakeLogbookReportModel(LogbookOperationType.RET, secondLogbookReportGroupDatOperation.reportId), - ) - - val thirdLogbookReportGroupDatOperation = getFakeLogbookReportModel(LogbookOperationType.DAT) - val thirdLogbookReportGroupCorOperation = getFakeLogbookReportModel( - LogbookOperationType.COR, - thirdLogbookReportGroupDatOperation.reportId, - ) - val thirdLogbookReportGroup = listOf( - thirdLogbookReportGroupDatOperation, - getFakeLogbookReportModel(LogbookOperationType.RET, thirdLogbookReportGroupDatOperation.reportId), - thirdLogbookReportGroupCorOperation, - getFakeLogbookReportModel(LogbookOperationType.RET, thirdLogbookReportGroupCorOperation.reportId), - getFakeLogbookReportModel(LogbookOperationType.DEL, thirdLogbookReportGroupDatOperation.reportId), - ) - - val fourthLogbookReportGroupDatOperation = getFakeLogbookReportModel(LogbookOperationType.COR) - val fourthLogbookReportGroup = listOf( - fourthLogbookReportGroupDatOperation, - getFakeLogbookReportModel(LogbookOperationType.RET, fourthLogbookReportGroupDatOperation.reportId), - ) - - val fifthLogbookReportGroupDatOperation = getFakeLogbookReportModel( - LogbookOperationType.COR, - "NONEXISTENT_REPORT_ID", - ) - val fifthLogbookReportGroup = listOf( - fifthLogbookReportGroupDatOperation, - getFakeLogbookReportModel(LogbookOperationType.RET, fifthLogbookReportGroupDatOperation.reportId), - ) - - val logbookReportModels = listOf( - firstLogbookReportGroup, - secondLogbookReportGroup, - thirdLogbookReportGroup, - fourthLogbookReportGroup, - fifthLogbookReportGroup, - ).flatten() - - // When - val result = JpaLogbookReportRepository.mapToReferenceWithRelatedModels(logbookReportModels) - - // Then - - assertThat(result).hasSize(5) - - val (firstReferenceLogbookReportModel, firstRelatedLogbookReportModels) = result[0] - assertThat(firstReferenceLogbookReportModel.reportId).isEqualTo(firstLogbookReportGroupDatOperation.reportId) - assertThat(firstReferenceLogbookReportModel.operationType).isEqualTo(LogbookOperationType.DAT) - assertThat(firstRelatedLogbookReportModels).isEmpty() - - val (secondReferenceLogbookReportModel, secondRelatedLogbookReportModels) = result[1] - assertThat(secondReferenceLogbookReportModel.reportId).isEqualTo(secondLogbookReportGroupDatOperation.reportId) - assertThat(secondReferenceLogbookReportModel.operationType).isEqualTo(LogbookOperationType.DAT) - assertThat(secondRelatedLogbookReportModels).hasSize(1) - assertThat(secondRelatedLogbookReportModels.count { it.operationType == LogbookOperationType.RET }).isEqualTo(1) - - val (thirdReferenceLogbookReportModel, thirdRelatedLogbookReportModels) = result[2] - assertThat(thirdReferenceLogbookReportModel.reportId).isEqualTo(thirdLogbookReportGroupDatOperation.reportId) - assertThat(thirdReferenceLogbookReportModel.operationType).isEqualTo(LogbookOperationType.DAT) - assertThat(thirdRelatedLogbookReportModels).hasSize(4) - assertThat(thirdRelatedLogbookReportModels.count { it.operationType == LogbookOperationType.COR }).isEqualTo(1) - assertThat(thirdRelatedLogbookReportModels.count { it.operationType == LogbookOperationType.DEL }).isEqualTo(1) - assertThat(thirdRelatedLogbookReportModels.count { it.operationType == LogbookOperationType.RET }).isEqualTo(2) - - val (fourthReferenceLogbookReportModel, fourthRelatedLogbookReportModels) = result[3] - assertThat(fourthReferenceLogbookReportModel.reportId).isEqualTo(fourthLogbookReportGroupDatOperation.reportId) - assertThat(fourthReferenceLogbookReportModel.operationType).isEqualTo(LogbookOperationType.COR) - assertThat(fourthRelatedLogbookReportModels).hasSize(1) - assertThat(fourthRelatedLogbookReportModels.count { it.operationType == LogbookOperationType.RET }).isEqualTo(1) - - val (fifthReferenceLogbookReportModel, fifthRelatedLogbookReportModels) = result[4] - assertThat(fifthReferenceLogbookReportModel.reportId).isEqualTo(fifthLogbookReportGroupDatOperation.reportId) - assertThat(fifthReferenceLogbookReportModel.operationType).isEqualTo(LogbookOperationType.COR) - assertThat(fifthRelatedLogbookReportModels).hasSize(1) - assertThat(fifthRelatedLogbookReportModels.count { it.operationType == LogbookOperationType.RET }).isEqualTo(1) - } - @Test @Transactional fun `findLastReportSoftware Should return the software of the last message`() { From 6bd2b7fadec445888b0a3cbc363ad8fd5c8d2dce Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 13:48:06 +0200 Subject: [PATCH 05/26] Add chain resolution in JpaLogbookReportRepository.findAllPriorNotifications() --- .../prior_notification/PriorNotification.kt | 15 +++ .../database/entities/LogbookReportEntity.kt | 13 +- .../JpaLogbookReportRepository.kt | 112 +++++++++--------- 3 files changed, 80 insertions(+), 60 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt index 5a53876cf9..864413ff46 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt @@ -3,6 +3,7 @@ package fr.gouv.cnsp.monitorfish.domain.entities.prior_notification import fr.gouv.cnsp.monitorfish.domain.entities.facade.Seafront import fr.gouv.cnsp.monitorfish.domain.entities.gear.Gear import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessageAndValue +import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.Acknowledgment import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO import fr.gouv.cnsp.monitorfish.domain.entities.port.Port import fr.gouv.cnsp.monitorfish.domain.entities.reporting.ReportingType @@ -136,6 +137,20 @@ data class PriorNotification( reportingCount = currentReportings?.count() ?: 0 } + fun markAsAcknowledged() { + logbookMessageAndValue = LogbookMessageAndValue( + logbookMessageAndValue.logbookMessage.copy(acknowledgment = Acknowledgment(isSuccess = true)), + PNO::class.java, + ) + } + + fun markAsDeleted() { + logbookMessageAndValue = LogbookMessageAndValue( + logbookMessageAndValue.logbookMessage.copy(isDeleted = true), + PNO::class.java, + ) + } + companion object { private val logger = LoggerFactory.getLogger(PriorNotification::class.java) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt index 9105d82224..82571a8baf 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt @@ -141,10 +141,11 @@ data class LogbookReportEntity( } fun toPriorNotification(mapper: ObjectMapper): PriorNotification { - val referenceLogbookMessage = toLogbookMessage(mapper) - - val consolidatedLogbookMessageAndValue = referenceLogbookMessage - .toConsolidatedLogbookMessageAndValue(PNO::class.java) + val logbookMessage = toLogbookMessage(mapper) + val logbookMessageAndValue = LogbookMessageAndValue( + logbookMessage = logbookMessage, + clazz = PNO::class.java, + ) val updatedAt = operationDateTime.atZone(UTC) // For practical reasons `vessel` can't be `null`, so we temporarily set it to "Navire inconnu" val vessel = UNKNOWN_VESSEL @@ -154,8 +155,8 @@ data class LogbookReportEntity( createdAt = operationDateTime.atZone(UTC), didNotFishAfterZeroNotice = false, isManuallyCreated = false, - logbookMessageAndValue = consolidatedLogbookMessageAndValue, - sentAt = consolidatedLogbookMessageAndValue.logbookMessage.reportDateTime, + logbookMessageAndValue = logbookMessageAndValue, + sentAt = logbookMessageAndValue.logbookMessage.reportDateTime, updatedAt = updatedAt, // These props need to be calculated in the use case diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 7076e6ab0a..9754b00ded 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import fr.gouv.cnsp.monitorfish.Utils import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessage import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessageAndValue +import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookOperationType import fr.gouv.cnsp.monitorfish.domain.entities.logbook.VoyageDatesAndTripNumber import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotification @@ -36,66 +37,45 @@ class JpaLogbookReportRepository( private val logger = LoggerFactory.getLogger(JpaLogbookReportRepository::class.java) override fun findAllPriorNotifications(filter: PriorNotificationsFilter): List { - val logbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( - flagStates = filter.flagStates ?: emptyList(), - hasOneOrMoreReportings = filter.hasOneOrMoreReportings, - isLessThanTwelveMetersVessel = filter.isLessThanTwelveMetersVessel, - lastControlledAfter = filter.lastControlledAfter, - lastControlledBefore = filter.lastControlledBefore, - portLocodes = filter.portLocodes ?: emptyList(), - priorNotificationTypesAsSqlArrayString = toSqlArrayString(filter.priorNotificationTypes), - searchQuery = filter.searchQuery, - specyCodesAsSqlArrayString = toSqlArrayString(filter.specyCodes), - tripGearCodesAsSqlArrayString = toSqlArrayString(filter.tripGearCodes), - tripSegmentCodesAsSqlArrayString = toSqlArrayString(filter.tripSegmentCodes), - willArriveAfter = filter.willArriveAfter, - willArriveBefore = filter.willArriveBefore, - ) - - return logbookReportModels.mapNotNull { logbookReportModel -> - try { - logbookReportModel.toPriorNotification(objectMapper) - } catch (e: Exception) { - logger.warn( - "Error while converting logbook report model to prior notification (reportId = ${logbookReportModel.reportId}).", - e, - ) + // Acknowledged "DAT", "COR" and "DEL" operations + val logbookReportModelsWithCorAndDel = + dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( + flagStates = filter.flagStates ?: emptyList(), + hasOneOrMoreReportings = filter.hasOneOrMoreReportings, + isLessThanTwelveMetersVessel = filter.isLessThanTwelveMetersVessel, + lastControlledAfter = filter.lastControlledAfter, + lastControlledBefore = filter.lastControlledBefore, + portLocodes = filter.portLocodes ?: emptyList(), + priorNotificationTypesAsSqlArrayString = toSqlArrayString(filter.priorNotificationTypes), + searchQuery = filter.searchQuery, + specyCodesAsSqlArrayString = toSqlArrayString(filter.specyCodes), + tripGearCodesAsSqlArrayString = toSqlArrayString(filter.tripGearCodes), + tripSegmentCodesAsSqlArrayString = toSqlArrayString(filter.tripSegmentCodes), + willArriveAfter = filter.willArriveAfter, + willArriveBefore = filter.willArriveBefore, + ) - null + val datAndOrphanCorLogbooReportModels = logbookReportModelsWithCorAndDel + .filter { + it.operationType == LogbookOperationType.DAT || ( + it.operationType == LogbookOperationType.COR && + logbookReportModelsWithCorAndDel.none { model -> model.reportId == it.referencedReportId } + ) } + + return datAndOrphanCorLogbooReportModels.map { + resolveAsPriorNotification(it, logbookReportModelsWithCorAndDel, objectMapper) } } @Cacheable(value = ["pno_to_verify"]) override fun findAllPriorNotificationsToVerify(): List { - val logbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( - flagStates = emptyList(), - hasOneOrMoreReportings = null, - isLessThanTwelveMetersVessel = null, - lastControlledAfter = null, - lastControlledBefore = null, - portLocodes = emptyList(), - priorNotificationTypesAsSqlArrayString = null, - searchQuery = null, - specyCodesAsSqlArrayString = null, - tripGearCodesAsSqlArrayString = null, - tripSegmentCodesAsSqlArrayString = null, + val filter = PriorNotificationsFilter( willArriveAfter = CustomZonedDateTime(ZonedDateTime.now()).toString(), willArriveBefore = CustomZonedDateTime(ZonedDateTime.now().plusHours(24)).toString(), ) - return logbookReportModels.mapNotNull { referenceLogbookReportModel -> - try { - referenceLogbookReportModel.toPriorNotification(objectMapper) - } catch (e: Exception) { - logger.warn( - "Error while converting logbook report model to prior notifications (reportId = ${referenceLogbookReportModel.reportId}).", - e, - ) - - null - } - }.filter { + return findAllPriorNotifications(filter).filter { it.logbookMessageAndValue.value.isInVerificationScope == true && it.logbookMessageAndValue.value.isVerified == false && it.logbookMessageAndValue.value.isInvalidated != true @@ -419,11 +399,10 @@ class JpaLogbookReportRepository( @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val logbookReportModel = - dbLogbookReportRepository.findByReportId( - reportId, - operationDate.withZoneSameInstant(UTC).toString(), - ) + val logbookReportModel = dbLogbookReportRepository.findByReportId( + reportId, + operationDate.withZoneSameInstant(UTC).toString(), + ) if (logbookReportModel == null) { throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) } @@ -439,4 +418,29 @@ class JpaLogbookReportRepository( private fun getAllMessagesExceptionMessage(internalReferenceNumber: String) = "No messages found for the vessel. (internalReferenceNumber: \"$internalReferenceNumber\")" + + companion object { + private fun resolveAsPriorNotification( + parent: LogbookReportEntity, + list: List, + objectMapper: ObjectMapper, + ): PriorNotification { + val child = list.find { it.referencedReportId == parent.reportId } + if (child?.reportId == null) { + val datOrCorParent = parent.toPriorNotification(objectMapper) + datOrCorParent.markAsAcknowledged() + + return datOrCorParent + } + if (child.operationType == LogbookOperationType.DEL) { + val delParent = parent.toPriorNotification(objectMapper) + delParent.markAsAcknowledged() + delParent.markAsDeleted() + + return delParent + } + + return resolveAsPriorNotification(child, list, objectMapper) + } + } } From d34b3db00385aa74373f351124401279e24dd15b Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 13:49:34 +0200 Subject: [PATCH 06/26] Add missing RETs in pno logbook reports test data --- ...6.5.1__Insert_more_pno_logbook_reports.sql | 108 ++++++-- ...5.1__Insert_more_pno_logbook_reports.jsonc | 253 +++++++++++++++--- 2 files changed, 297 insertions(+), 64 deletions(-) diff --git a/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql b/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql index 931a3ca5cd..d42b5edfec 100644 --- a/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql +++ b/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql @@ -3,16 +3,28 @@ INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_101', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_101_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_102', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_102_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_103', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_103_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_104', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_104_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_105', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_105_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_106', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_106_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_107', 'Message FLUX xml'); INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_107_RET', 'Message FLUX xml'); @@ -23,95 +35,143 @@ INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_O INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_109', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_109_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_109_COR', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_109_COR_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_110', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_110_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_110_DEL', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_110_DEL_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_111_COR_ORPHAN', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_111_COR_ORPHAN_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_112', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_112_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_113', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_113_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_114', 'Message FLUX xml'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_114_RET', 'Message FLUX xml'); + INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_115', 'Message FLUX xml'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (101, 'FAKE_OPERATION_101', NULL, 'FAK000999999', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_101', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'PHENOMENE', '[{"gear":"TBN","mesh":100,"dimensions":"250;180"},{"gear":"OTT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW04","segmentName":"Chaluts pélagiques"},{"segment":"SWW06","segmentName":"Sennes"}]', '{"riskFactor":2.1,"catchOnboard":[{"weight":25,"nbFish":null,"species":"COD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_115_RET', 'Message FLUX xml'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (101, 'FAKE_OPERATION_101', NULL, 'FAK000999999', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_101', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', 'PHENOMENE', '[{"gear":"TBN","mesh":100,"dimensions":"250;180"},{"gear":"OTT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW04","segmentName":"Chaluts pélagiques"},{"segment":"SWW06","segmentName":"Sennes"}]', '{"riskFactor":2.1,"catchOnboard":[{"weight":25,"nbFish":null,"species":"COD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 101; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 101; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 101; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (102, 'FAKE_OPERATION_102', NULL, 'ABC000042310', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_102', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'COURANT MAIN PROFESSEUR', '[{"gear":"PT","mesh":100,"dimensions":"250;180"},{"gear":"OT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW10","segmentName":"Palangres ciblant les espèces démersales"},{"segment":"SWW11","segmentName":"Hameçons"}]', '{"riskFactor":2.8,"catchOnboard":[{"weight":25,"nbFish":null,"species":"SOL","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":25,"nbFish":null,"species":"HKE","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type C","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRBES","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1101, NULL, 'FAKE_OPERATION_101', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_101_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (102, 'FAKE_OPERATION_102', NULL, 'ABC000042310', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_102', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', 'COURANT MAIN PROFESSEUR', '[{"gear":"PT","mesh":100,"dimensions":"250;180"},{"gear":"OT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW10","segmentName":"Palangres ciblant les espèces démersales"},{"segment":"SWW11","segmentName":"Hameçons"}]', '{"riskFactor":2.8,"catchOnboard":[{"weight":25,"nbFish":null,"species":"SOL","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":25,"nbFish":null,"species":"HKE","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type C","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRBES","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '4 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 102; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 102; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 102; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (103, 'FAKE_OPERATION_103', NULL, NULL, true, NULL, '2023-12-31 17:00:00', 'PNO', '2023-12-31 17:00:00', 'FAKE_OPERATION_103', 'DAT', '2023-12-31 17:00:00', 'JT/VISIOCaptures V1.4.7', 'ERS', NULL, '[]', '[]', '{"riskFactor":1.8,"catchOnboard":[],"pnoTypes":[],"port":"AEHZP","predictedArrivalDatetimeUtc":"2023-12-31T23:59:00Z","purpose":"GRD","tripStartDate":"2023-12-31T06:00:00Z"}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1102, NULL, 'FAKE_OPERATION_102', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_102_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (103, 'FAKE_OPERATION_103', NULL, NULL, true, NULL, '2023-12-31 17:00:00', 'PNO', '2023-12-31 17:00:00', 'FAKE_OPERATION_103', 'DAT', '2023-12-31 17:00:00', 'ERS', NULL, '[]', '[]', '{"riskFactor":1.8,"catchOnboard":[],"pnoTypes":[],"port":"AEHZP","predictedArrivalDatetimeUtc":"2023-12-31T23:59:00Z","purpose":"GRD","tripStartDate":"2023-12-31T06:00:00Z"}'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (104, 'FAKE_OPERATION_104', NULL, 'CFR101', true, 'ESP', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_104', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'VIVA ESPANA', '[{"gear":"TB","mesh":100,"dimensions":"250;180"},{"gear":"TBS","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde"},{"segment":"NWW05","segmentName":"Chalut à perche"}]', '{"riskFactor":2.2,"catchOnboard":[{"weight":25,"nbFish":null,"species":"FRF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":150,"nbFish":null,"species":"AFH","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":250,"nbFish":null,"species":"AFI","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":75,"nbFish":null,"species":"AFT","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":10,"nbFish":null,"species":"AFU","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":430,"nbFish":null,"species":"APX","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":90,"nbFish":null,"species":"AQD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":true,"isSent":true,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRVNE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1103, NULL, 'FAKE_OPERATION_103', '2023-12-31 17:00:00', '2023-12-31 17:00:00', 'FAKE_OPERATION_103_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (104, 'FAKE_OPERATION_104', NULL, 'CFR101', true, 'ESP', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_104', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', 'VIVA ESPANA', '[{"gear":"TB","mesh":100,"dimensions":"250;180"},{"gear":"TBS","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde"},{"segment":"NWW05","segmentName":"Chalut à perche"}]', '{"riskFactor":2.2,"catchOnboard":[{"weight":25,"nbFish":null,"species":"FRF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":150,"nbFish":null,"species":"AFH","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":250,"nbFish":null,"species":"AFI","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":75,"nbFish":null,"species":"AFT","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":10,"nbFish":null,"species":"AFU","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":430,"nbFish":null,"species":"APX","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":90,"nbFish":null,"species":"AQD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":true,"isSent":true,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRVNE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 104; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '4 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 104; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 104; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (105, 'FAKE_OPERATION_105', NULL, 'CFR102', true, 'NLD', '2024-03-01 15:00:00', 'PNO', '2024-03-01 15:00:00', 'FAKE_OPERATION_105', 'DAT', '2024-03-01 15:00:00', 'JT/VISIOCaptures V1.4.7', 'ERS', 'LEVE NEDERLAND', '[{"gear":"DHB","mesh":20.25,"dimensions":"500;500"},{"gear":"DRM","mesh":25.75,"dimensions":"1000;1000"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde ≥100 mm"}]', '{"riskFactor":1.9,"catchOnboard":[{"weight":25,"nbFish":null,"species":"FRF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRVNE","predictedArrivalDatetimeUtc":"2024-03-01T17:00:00Z","predictedLandingDatetimeUtc":"2024-03-01T17:30:00Z","purpose":"LAN","tripStartDate":"2024-03-01T05:00:00Z"}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1104, NULL, 'FAKE_OPERATION_104', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_104_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (105, 'FAKE_OPERATION_105', NULL, 'CFR102', true, 'NLD', '2024-03-01 15:00:00', 'PNO', '2024-03-01 15:00:00', 'FAKE_OPERATION_105', 'DAT', '2024-03-01 15:00:00', 'ERS', 'LEVE NEDERLAND', '[{"gear":"DHB","mesh":20.25,"dimensions":"500;500"},{"gear":"DRM","mesh":25.75,"dimensions":"1000;1000"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde ≥100 mm"}]', '{"riskFactor":1.9,"catchOnboard":[{"weight":25,"nbFish":null,"species":"FRF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRVNE","predictedArrivalDatetimeUtc":"2024-03-01T17:00:00Z","predictedLandingDatetimeUtc":"2024-03-01T17:30:00Z","purpose":"LAN","tripStartDate":"2024-03-01T05:00:00Z"}'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (106, 'FAKE_OPERATION_106', NULL, 'CFR103', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_106', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'L''OM DU POISSON', '[{"gear":"DHB","mesh":20.25,"dimensions":"500;500"},{"gear":"DRM","mesh":25.75,"dimensions":"1000;1000"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde ≥100 mm"}]', '{"riskFactor":2.5,"catchOnboard":[{"weight":25,"nbFish":null,"species":"FRF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":true,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type E","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRMRS","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1105, NULL, 'FAKE_OPERATION_105', '2024-03-01 15:00:00', '2024-03-01 15:00:00', 'FAKE_OPERATION_105_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (106, 'FAKE_OPERATION_106', NULL, 'CFR103', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_106', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', 'L''OM DU POISSON', '[{"gear":"DHB","mesh":20.25,"dimensions":"500;500"},{"gear":"DRM","mesh":25.75,"dimensions":"1000;1000"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde ≥100 mm"}]', '{"riskFactor":2.5,"catchOnboard":[{"weight":25,"nbFish":null,"species":"FRF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":true,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type E","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRMRS","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 106; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '4 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 106; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 106; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (107, 'FAKE_OPERATION_107', NULL, 'CFR104', true, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_107', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', '[{"gear":"DHB","mesh":20.25,"dimensions":"500;500"},{"gear":"DRM","mesh":25.75,"dimensions":"1000;1000"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde ≥100 mm"}]', 'DES BARS', '{"riskFactor":3.4,"catchOnboard":[{"weight":25,"nbFish":null,"species":"COD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":true,"isInVerificationScope":true,"isSent":false,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1106, NULL, 'FAKE_OPERATION_106', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_106_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (107, 'FAKE_OPERATION_107', NULL, 'CFR104', true, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_107', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', '[{"gear":"DHB","mesh":20.25,"dimensions":"500;500"},{"gear":"DRM","mesh":25.75,"dimensions":"1000;1000"}]', '[{"segment":"NWW03","segmentName":"Chalut de fond en eau profonde ≥100 mm"}]', 'DES BARS', '{"riskFactor":3.4,"catchOnboard":[{"weight":25,"nbFish":null,"species":"COD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":true,"isInVerificationScope":true,"isSent":false,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 107; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 107; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 107; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (1107, NULL, 'FAKE_OPERATION_107', 'CFR104', false, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_107_RET', 'RET', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', NULL, NULL, NULL, '{"returnStatus":"000"}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1107, NULL, 'FAKE_OPERATION_107', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_107_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (108, 'FAKE_OPERATION_108', NULL, 'CFR105', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_108', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'TurboCatch (3.7-1)', 'ERS', NULL, NULL, 'CALAMARO', '{"riskFactor":2.9,"catchOnboard":[{"weight":150,"nbFish":null,"species":"ANF","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 108; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 108; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 108; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (1108, NULL, 'FAKE_OPERATION_108', 'CFR105', false, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_108_RET', 'RET', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'TurboCatch (3.7-1)', 'ERS', NULL, NULL, NULL, '{"rejectionCause":"002 MGEN02 Message incorrect : la date/heure de l''événement RTP n° OOF20201105037001 est postérieure à la date/heure courante. Veuillez vérifier la date/heure de l''événement déclaré et renvoyer votre message.","returnStatus":"002"}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1108, NULL, 'FAKE_OPERATION_108', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_108_RET', 'RET', 'ERS', '{"rejectionCause":"002 MGEN02 Message incorrect : la date/heure de l''événement RTP n° OOF20201105037001 est postérieure à la date/heure courante. Veuillez vérifier la date/heure de l''événement déclaré et renvoyer votre message.","returnStatus":"002"}'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (109, 'FAKE_OPERATION_109', NULL, 'CFR106', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_109', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', NULL, NULL, 'L''ANCRE SÈCHE', '{"riskFactor":2.2,"catchOnboard":[],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (109, 'FAKE_OPERATION_109', NULL, 'CFR106', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_109', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', NULL, NULL, 'L''ANCRE SÈCHE', '{"riskFactor":2.2,"catchOnboard":[],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 109; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 109; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 109; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (1109, 'FAKE_OPERATION_109_COR', 'FAKE_OPERATION_109', 'CFR106', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_109_COR', 'COR', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'L''ANCRE SÈCHE', NULL, NULL, '{"riskFactor":1.7,"catchOnboard":[{"economicZone":"FRA","effortZone":"C","faoZone":"27.8.a","nbFish":null,"species":"BHX","statisticalRectangle":"23E6","weight":32.5}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRVNE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); -UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 1109; -UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 1109; -UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 1109; +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1109, NULL, 'FAKE_OPERATION_109', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_109_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (2109, 'FAKE_OPERATION_109_COR', 'FAKE_OPERATION_109', 'CFR106', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_109_COR', 'COR', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'ERS', 'L''ANCRE SÈCHE', NULL, NULL, '{"riskFactor":1.7,"catchOnboard":[{"economicZone":"FRA","effortZone":"C","faoZone":"27.8.a","nbFish":null,"species":"BHX","statisticalRectangle":"23E6","weight":32.5}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRVNE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 2109; +UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 2109; +UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 2109; + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (3109, NULL, 'FAKE_OPERATION_109_COR', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_109_COR_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (110, 'FAKE_OPERATION_110', NULL, 'CFR107', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_110', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', NULL, NULL, 'MERLU L''ENCHANTEUR', '{"riskFactor":2.1,"catchOnboard":[{"economicZone":"FRA","effortZone":"C","faoZone":"27.8.a","nbFish":null,"species":"COD","statisticalRectangle":"23E6","weight":25}],"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRBES","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (110, 'FAKE_OPERATION_110', NULL, 'CFR107', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_110', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', NULL, NULL, 'MERLU L''ENCHANTEUR', '{"riskFactor":2.1,"catchOnboard":[{"economicZone":"FRA","effortZone":"C","faoZone":"27.8.a","nbFish":null,"species":"COD","statisticalRectangle":"23E6","weight":25}],"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRBES","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 110; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 110; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 110; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (1110, NULL, 'FAKE_OPERATION_110', 'FR263418260', false, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_110_DEL', 'DEL', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', NULL, NULL, NULL, NULL); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1110, NULL, 'FAKE_OPERATION_110', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_110_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (1111, 'FAKE_OPERATION_111_COR_ORPHAN', 'FAKE_OPERATION_111', 'CFR108', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_111_COR_ORPHAN', 'COR', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'LE POISSON AMBULANT', NULL, NULL, '{"riskFactor":3.1,"catchOnboard":[{"economicZone":"FRA","effortZone":"C","faoZone":"27.8.a","nbFish":null,"species":"COD","statisticalRectangle":"23E6","weight":25}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRNCE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); -UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 1111; -UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 1111; -UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 1111; +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (2110, 'FAKE_OPERATION_110_DEL', 'FAKE_OPERATION_110', 'CFR107', false, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_110_DEL', 'DEL', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'ERS', NULL, NULL, NULL, NULL); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (112, 'FAKE_OPERATION_112', NULL, NULL, false, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_112', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', NULL, NULL, NULL, NULL); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (3110, NULL, 'FAKE_OPERATION_110_DEL', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_110_DEL_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (113, 'FAKE_OPERATION_113', NULL, 'CFR109', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_113', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'FLUX', '[{"gear":"DRB","mesh":null,"dimensions":null}]', '[{"segment":"FR_SCE","segmentName":"Scallop fisheries"}]', 'LE POISSON AMBULANT', '{"riskFactor":3.9,"catchOnboard":[{"nbFish":null,"weight":40,"faoZone":"27.7.d","species":"ANF","effortZone":null,"economicZone":"FRA","statisticalRectangle":null},{"nbFish":null,"weight":3,"faoZone":"27.7.d","species":"SOL","effortZone":null,"economicZone":"FRA","statisticalRectangle":null},{"nbFish":null,"weight":16,"faoZone":"27.7.d","species":"TUR","effortZone":null,"economicZone":"FRA","statisticalRectangle":null},{"nbFish":null,"weight":27150,"faoZone":"27.7.d","species":"SCE","effortZone":null,"economicZone":"FRA","statisticalRectangle":null}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Autres espèces soumises à préavis","hasDesignatedPorts":true,"minimumNotificationPeriod":4},{"pnoTypeName":"Préavis navire tiers","hasDesignatedPorts":true,"minimumNotificationPeriod":4}],"port":"FRVNE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (2111, 'FAKE_OPERATION_111_COR_ORPHAN', 'FAKE_OPERATION_111', 'CFR108', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_111_COR_ORPHAN', 'COR', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'ERS', 'LE POISSON AMBULANT', NULL, NULL, '{"riskFactor":3.1,"catchOnboard":[{"economicZone":"FRA","effortZone":"C","faoZone":"27.8.a","nbFish":null,"species":"COD","statisticalRectangle":"23E6","weight":25}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type Z","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRNCE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 2111; +UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 2111; +UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 2111; + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (3111, NULL, 'FAKE_OPERATION_111_COR_ORPHAN', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_111_COR_ORPHAN_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (112, 'FAKE_OPERATION_112', NULL, NULL, false, NULL, NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_112', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', NULL, NULL, NULL, NULL); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1112, NULL, 'FAKE_OPERATION_112', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_112_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, trip_gears, trip_segments, vessel_name, value) VALUES (113, 'FAKE_OPERATION_113', NULL, 'CFR109', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_113', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FLUX', '[{"gear":"DRB","mesh":null,"dimensions":null}]', '[{"segment":"FR_SCE","segmentName":"Scallop fisheries"}]', 'LE POISSON AMBULANT', '{"riskFactor":3.9,"catchOnboard":[{"nbFish":null,"weight":40,"faoZone":"27.7.d","species":"ANF","effortZone":null,"economicZone":"FRA","statisticalRectangle":null},{"nbFish":null,"weight":3,"faoZone":"27.7.d","species":"SOL","effortZone":null,"economicZone":"FRA","statisticalRectangle":null},{"nbFish":null,"weight":16,"faoZone":"27.7.d","species":"TUR","effortZone":null,"economicZone":"FRA","statisticalRectangle":null},{"nbFish":null,"weight":27150,"faoZone":"27.7.d","species":"SCE","effortZone":null,"economicZone":"FRA","statisticalRectangle":null}],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Autres espèces soumises à préavis","hasDesignatedPorts":true,"minimumNotificationPeriod":4},{"pnoTypeName":"Préavis navire tiers","hasDesignatedPorts":true,"minimumNotificationPeriod":4}],"port":"FRVNE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 113; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 113; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 113; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (114, 'FAKE_OPERATION_114', NULL, 'CFR110', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'FAKE_OPERATION_114', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'JT/VISIOCaptures V1.4.7', 'ERS', 'LA MER À BOIRE', '[]', '[]', '{"catchOnboard":[],"pnoTypes":[],"port":null,"predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1113, NULL, 'FAKE_OPERATION_113', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_113_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (114, 'FAKE_OPERATION_114', NULL, 'CFR110', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'FAKE_OPERATION_114', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'ERS', 'LA MER À BOIRE', '[]', '[]', '{"catchOnboard":[],"pnoTypes":[],"port":null,"predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '1 hour', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 114; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '2 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 114; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '20 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 114; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (115, 'FAKE_OPERATION_115', NULL, 'CFR111', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'FAKE_OPERATION_115', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'JT/VISIOCaptures V1.4.7', 'ERS', 'LE MARIN D''EAU DOUCE', '[]', '[]', '{"riskFactor":2.9,"catchOnboard":[],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[],"port":"REZSE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1114, NULL, 'FAKE_OPERATION_114', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_114_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (115, 'FAKE_OPERATION_115', NULL, 'CFR111', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'FAKE_OPERATION_115', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours', 'ERS', 'LE MARIN D''EAU DOUCE', '[]', '[]', '{"riskFactor":2.9,"catchOnboard":[],"isBeingSent":false,"isInVerificationScope":false,"isSent":false,"isVerified":false,"pnoTypes":[],"port":"REZSE","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '1 hour', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 115; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '2 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 115; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '20 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 115; + +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1115, NULL, 'FAKE_OPERATION_115', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_115_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); diff --git a/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc b/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc index 17ac1a95ab..baf2865312 100644 --- a/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc +++ b/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc @@ -3,24 +3,39 @@ "table": "logbook_raw_messages", "data": [ { "operation_number": "FAKE_OPERATION_101", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_101_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_102", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_102_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_103", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_103_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_104", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_104_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_105", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_105_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_106", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_106_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_107", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_107_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_108", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_108_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_109", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_109_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_109_COR", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_109_COR_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_110", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_110_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_110_DEL", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_110_DEL_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_111_COR_ORPHAN", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_111_COR_ORPHAN_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_112", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_112_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_113", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_113_RET", "xml_message": "Message FLUX xml" }, { "operation_number": "FAKE_OPERATION_114", "xml_message": "Message FLUX xml" }, - { "operation_number": "FAKE_OPERATION_115", "xml_message": "Message FLUX xml" } + { "operation_number": "FAKE_OPERATION_114_RET", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_115", "xml_message": "Message FLUX xml" }, + { "operation_number": "FAKE_OPERATION_115_RET", "xml_message": "Message FLUX xml" } ] }, { @@ -42,7 +57,6 @@ "operation_number": "FAKE_OPERATION_101", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "PHENOMENE", "trip_gears:jsonb": [ @@ -89,6 +103,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 1101, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_101", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_101_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: COURANT MAIN PROFESSEUR // - With 1 reporting @@ -106,7 +133,6 @@ "operation_number": "FAKE_OPERATION_102", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "COURANT MAIN PROFESSEUR", "trip_gears:jsonb": [ @@ -157,6 +183,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 1102, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_102", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_102_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: UNKNOWN // - Purpose: GRD @@ -173,7 +212,6 @@ "operation_number": "FAKE_OPERATION_103", "operation_type": "DAT", "report_datetime_utc": "2023-12-31 17:00:00", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": null, "trip_gears:jsonb": [], @@ -188,6 +226,19 @@ "tripStartDate": "2023-12-31T06:00:00Z" } }, + { + "id": 1103, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_103", + "integration_datetime_utc": "2023-12-31 17:00:00", + "operation_datetime_utc": "2023-12-31 17:00:00", + "operation_number": "FAKE_OPERATION_103_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: VIVA ESPANA // - With 2 reportings @@ -208,7 +259,6 @@ "operation_number": "FAKE_OPERATION_104", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "VIVA ESPANA", "trip_gears:jsonb": [ @@ -309,6 +359,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 1104, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_104", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_104_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: LEVE NEDERLAND // - Flag state: NL @@ -325,7 +388,6 @@ "operation_number": "FAKE_OPERATION_105", "operation_type": "DAT", "report_datetime_utc": "2024-03-01 15:00:00", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "LEVE NEDERLAND", "trip_gears:jsonb": [ @@ -371,6 +433,19 @@ "tripStartDate": "2024-03-01T05:00:00Z" } }, + { + "id": 1105, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_105", + "integration_datetime_utc": "2024-03-01 15:00:00", + "operation_datetime_utc": "2024-03-01 15:00:00", + "operation_number": "FAKE_OPERATION_105_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: L'OM DU POISSON // - State: Pending verification (required) @@ -387,7 +462,6 @@ "operation_number": "FAKE_OPERATION_106", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "L'OM DU POISSON", "trip_gears:jsonb": [ @@ -428,10 +502,21 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 1106, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_106", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_106_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: DES BARS - // - With RET - // - Aknowledged // - Flag state: UNKNOWN // - State: Unverified and pending sending { @@ -447,7 +532,6 @@ "operation_number": "FAKE_OPERATION_107", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "trip_gears:jsonb": [ { "gear": "DHB", "mesh": 20.25, "dimensions": "500;500" }, @@ -492,27 +576,17 @@ "id": 1107, "report_id": null, "referenced_report_id": "FAKE_OPERATION_107", - "cfr": "CFR104", - "enriched": false, - "flag_state": null, "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "log_type": null, "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", "operation_number": "FAKE_OPERATION_107_RET", "operation_type": "RET", - "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", - "trip_gears": null, - "trip_segments": null, - "vessel_name": null, "value:jsonb": { "returnStatus": "000" } }, // - Vessel: CALAMARO - // - With RET // - NOT Aknowledged { "id": 108, @@ -563,20 +637,11 @@ "id": 1108, "report_id": null, "referenced_report_id": "FAKE_OPERATION_108", - "cfr": "CFR105", - "enriched": false, - "flag_state": null, "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "log_type": null, "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", "operation_number": "FAKE_OPERATION_108_RET", "operation_type": "RET", - "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "software": "TurboCatch (3.7-1)", "transmission_format": "ERS", - "vessel_name": null, - "trip_gears": null, - "trip_segments": null, "value:jsonb": { "rejectionCause": "002 MGEN02 Message incorrect : la date/heure de l'événement RTP n° OOF20201105037001 est postérieure à la date/heure courante. Veuillez vérifier la date/heure de l'événement déclaré et renvoyer votre message.", "returnStatus": "002" @@ -598,7 +663,6 @@ "operation_number": "FAKE_OPERATION_109", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "trip_gears": null, "trip_segments": null, @@ -620,6 +684,19 @@ }, { "id": 1109, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_109", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_109_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, + { + "id": 2109, "report_id": "FAKE_OPERATION_109_COR", "referenced_report_id": "FAKE_OPERATION_109", "cfr": "CFR106", @@ -631,7 +708,6 @@ "operation_number": "FAKE_OPERATION_109_COR", "operation_type": "COR", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "L'ANCRE SÈCHE", "trip_gears": null, @@ -667,6 +743,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 3109, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_109_COR", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_109_COR_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: MERLU L'ENCHANTEUR // - With DEL @@ -683,7 +772,6 @@ "operation_number": "FAKE_OPERATION_110", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "trip_gears": null, "trip_segments": null, @@ -719,7 +807,20 @@ "id": 1110, "report_id": null, "referenced_report_id": "FAKE_OPERATION_110", - "cfr": "FR263418260", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_110_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, + { + "id": 2110, + "report_id": "FAKE_OPERATION_110_DEL", + "referenced_report_id": "FAKE_OPERATION_110", + "cfr": "CFR107", "enriched": false, "flag_state": null, "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", @@ -728,18 +829,30 @@ "operation_number": "FAKE_OPERATION_110_DEL", "operation_type": "DEL", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": null, "trip_gears": null, "trip_segments": null, "value": null }, + { + "id": 3110, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_110_DEL", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_110_DEL_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: LE POISSON AMBULANT // - Orphan COR (no DAT) { - "id": 1111, + "id": 2111, "report_id": "FAKE_OPERATION_111_COR_ORPHAN", // This `referenced_report_id` doesn't exist, this is intentional "referenced_report_id": "FAKE_OPERATION_111", @@ -752,7 +865,6 @@ "operation_number": "FAKE_OPERATION_111_COR_ORPHAN", "operation_type": "COR", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "LE POISSON AMBULANT", "trip_gears": null, @@ -788,6 +900,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 3111, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_111_COR_ORPHAN", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_111_COR_ORPHAN_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: UNKNOWN // - NOT Enriched @@ -804,13 +929,25 @@ "operation_number": "FAKE_OPERATION_112", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": null, "trip_gears": null, "trip_segments": null, "value": null }, + { + "id": 1112, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_112", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_112_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: LE POISSON D'AVRIL // - DUPLICATE Vessel CFR (= 2 `vessels` table rows with the same `cfr` value) @@ -827,7 +964,6 @@ "operation_number": "FAKE_OPERATION_113", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "FLUX", "trip_gears:jsonb": [{ "gear": "DRB", "mesh": null, "dimensions": null }], "trip_segments:jsonb": [{ "segment": "FR_SCE", "segmentName": "Scallop fisheries" }], @@ -895,6 +1031,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 1113, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_113", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_113_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: LA MER À BOIRE // - Without port (=> without seafront) @@ -911,7 +1060,6 @@ "operation_number": "FAKE_OPERATION_114", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "LA MER À BOIRE", "trip_gears:jsonb": [], @@ -926,6 +1074,19 @@ "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '20 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } }, + { + "id": 1114, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_114", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_114_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } + }, // - Vessel: LE MARIN D'EAU DOUCE // - Port: Saint-Denis De La Réunion (Sud Océan Indien) @@ -942,7 +1103,6 @@ "operation_number": "FAKE_OPERATION_115", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '6 hours'", - "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "LE MARIN D'EAU DOUCE", "trip_gears:jsonb": [], @@ -961,6 +1121,19 @@ "purpose": "LAN", "tripStartDate:sql": "TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '20 hours', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"')" } + }, + { + "id": 1115, + "report_id": null, + "referenced_report_id": "FAKE_OPERATION_115", + "integration_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", + "operation_number": "FAKE_OPERATION_115_RET", + "operation_type": "RET", + "transmission_format": "ERS", + "value:jsonb": { + "returnStatus": "000" + } } ] } From 21f81f1bed2dfedaaebfbdb0c92fdb8e9dbf13d3 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 13:51:04 +0200 Subject: [PATCH 07/26] Remove uncovered prior notification update cases in Backend unit tests --- .../JpaLogbookReportRepositoryITests.kt | 72 +++---------------- 1 file changed, 9 insertions(+), 63 deletions(-) diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt index e462729541..effbf988ab 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt @@ -5,12 +5,10 @@ import fr.gouv.cnsp.monitorfish.config.MapperConfiguration import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessagePurpose import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookOperationType import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookRawMessage -import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookTransmissionFormat import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.* import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.filters.PriorNotificationsFilter import fr.gouv.cnsp.monitorfish.domain.exceptions.NoLogbookFishingTripFound import fr.gouv.cnsp.monitorfish.domain.use_cases.TestUtils -import fr.gouv.cnsp.monitorfish.infrastructure.database.entities.LogbookReportEntity import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable import org.junit.jupiter.api.AfterEach @@ -21,10 +19,8 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.cache.CacheManager import org.springframework.context.annotation.Import import org.springframework.transaction.annotation.Transactional -import java.time.Instant import java.time.ZoneOffset.UTC import java.time.ZonedDateTime -import java.util.* @Import(MapperConfiguration::class) @SpringBootTest(properties = ["monitorfish.scheduling.enable=false"]) @@ -1037,16 +1033,13 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { @Transactional fun `updatePriorNotificationState Should update writable state values for an existing PNO logbook report`() { // Given - val currentDatReport = jpaLogbookReportRepository.findById(109) - assertThat((currentDatReport.message as PNO).isBeingSent).isEqualTo(false) - assertThat((currentDatReport.message as PNO).isVerified).isEqualTo(false) - val currentCorReport = jpaLogbookReportRepository.findById(1109) + val currentCorReport = jpaLogbookReportRepository.findById(2109) assertThat((currentCorReport.message as PNO).isBeingSent).isEqualTo(false) assertThat((currentCorReport.message as PNO).isVerified).isEqualTo(false) // When jpaLogbookReportRepository.updatePriorNotificationState( - "FAKE_OPERATION_109", + "FAKE_OPERATION_109_COR", ZonedDateTime.now().minusMinutes(15), isBeingSent = true, isSent = false, @@ -1054,10 +1047,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // Then - val updatedDatReport = jpaLogbookReportRepository.findById(109) - assertThat((updatedDatReport.message as PNO).isBeingSent).isEqualTo(true) - assertThat((updatedDatReport.message as PNO).isVerified).isEqualTo(true) - val updatedCorReport = jpaLogbookReportRepository.findById(1109) + val updatedCorReport = jpaLogbookReportRepository.findById(2109) assertThat((updatedCorReport.message as PNO).isBeingSent).isEqualTo(true) assertThat((updatedCorReport.message as PNO).isVerified).isEqualTo(true) } @@ -1066,26 +1056,19 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { @Transactional fun `updatePriorNotificationNote Should update a note for an existing PNO logbook report`() { // Given - val currentDatReport = jpaLogbookReportRepository.findById(109) - assertThat((currentDatReport.message as PNO).note).isNull() - val currentCorReport = jpaLogbookReportRepository.findById(1109) + val currentCorReport = jpaLogbookReportRepository.findById(2109) assertThat((currentCorReport.message as PNO).note).isNull() // When jpaLogbookReportRepository.updatePriorNotificationAuthorTrigramAndNote( - "FAKE_OPERATION_109", + "FAKE_OPERATION_109_COR", ZonedDateTime.now().minusMinutes(15), "ABC", "A wonderful note", ) // Then - val updatedDatReport = jpaLogbookReportRepository.findById(109) - assertThat((updatedDatReport.message as PNO).note).isEqualTo("A wonderful note") - assertThat((updatedDatReport.message as PNO).isBeingSent).isEqualTo(false) - assertThat((updatedDatReport.message as PNO).isVerified).isEqualTo(false) - assertThat((updatedDatReport.message as PNO).isSent).isEqualTo(false) - val updatedCorReport = jpaLogbookReportRepository.findById(1109) + val updatedCorReport = jpaLogbookReportRepository.findById(2109) assertThat((updatedCorReport.message as PNO).note).isEqualTo("A wonderful note") assertThat((updatedCorReport.message as PNO).isBeingSent).isEqualTo(false) assertThat((updatedCorReport.message as PNO).isVerified).isEqualTo(false) @@ -1096,54 +1079,17 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { @Transactional fun `invalidate Should invalidate for an existing PNO logbook report`() { // Given - val currentDatReport = jpaLogbookReportRepository.findById(109) - assertThat((currentDatReport.message as PNO).isInvalidated).isNull() - val currentCorReport = jpaLogbookReportRepository.findById(1109) + val currentCorReport = jpaLogbookReportRepository.findById(2109) assertThat((currentCorReport.message as PNO).isInvalidated).isNull() // When jpaLogbookReportRepository.invalidate( - "FAKE_OPERATION_109", + "FAKE_OPERATION_109_COR", ZonedDateTime.now().minusMinutes(15), ) // Then - val updatedDatReport = jpaLogbookReportRepository.findById(109) - assertThat((updatedDatReport.message as PNO).isInvalidated).isEqualTo(true) - val updatedCorReport = jpaLogbookReportRepository.findById(1109) + val updatedCorReport = jpaLogbookReportRepository.findById(2109) assertThat((updatedCorReport.message as PNO).isInvalidated).isEqualTo(true) } - - companion object { - private fun getFakeLogbookReportModel( - operationType: LogbookOperationType, - referenceReportId: String? = null, - ): LogbookReportEntity { - val reportId = UUID.randomUUID().toString() - - return LogbookReportEntity( - reportId = reportId, - referencedReportId = referenceReportId, - externalReferenceNumber = null, - flagState = null, - integrationDateTime = Instant.now(), - internalReferenceNumber = null, - imo = null, - ircs = null, - message = null, - messageType = null, - operationCountry = null, - operationDateTime = Instant.now(), - operationNumber = "FAKE_OPERATION_NUMBER_$reportId", - operationType = operationType, - reportDateTime = null, - software = null, - transmissionFormat = LogbookTransmissionFormat.ERS, - tripGears = null, - tripNumber = null, - tripSegments = null, - vesselName = null, - ) - } - } } From 9d2c15c9db74967b29d6f70627d3090d93810f46 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 13:55:13 +0200 Subject: [PATCH 08/26] Remove unused code in Backend --- .../domain/entities/logbook/LogbookMessage.kt | 67 +------------------ 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt index e95c32ee7c..fd2b6c7c22 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt @@ -4,7 +4,6 @@ import fr.gouv.cnsp.monitorfish.domain.entities.gear.Gear import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.* import fr.gouv.cnsp.monitorfish.domain.entities.port.Port import fr.gouv.cnsp.monitorfish.domain.entities.species.Species -import fr.gouv.cnsp.monitorfish.domain.exceptions.EntityConversionException import org.slf4j.LoggerFactory import java.time.ZonedDateTime @@ -51,30 +50,6 @@ data class LogbookMessage( return referencedReportId ?: reportId } - fun toConsolidatedLogbookMessageAndValue( - clazz: Class, - ): LogbookMessageAndValue { - if (reportId == null) { - throw EntityConversionException( - "Logbook report $id has no `reportId`. You can only enrich a DAT or an orphan COR operation with a `reportId`.", - ) - } - if (operationType !in listOf(LogbookOperationType.DAT, LogbookOperationType.COR)) { - throw EntityConversionException( - "Logbook report $id has operationType '$operationType'. You can only enrich a DAT or an orphan COR operation.", - ) - } - - // val logbookMessageBase = this - // logbookMessageBase.enrichAcnkowledge(relatedLogbookMessages) - // logbookMessageBase.enrichAcnkowledge(relatedLogbookMessages) - - return LogbookMessageAndValue( - logbookMessage = this, - clazz = clazz, - ) - } - fun setAcknowledge(newLogbookMessageAcknowledgement: LogbookMessage) { val currentAcknowledgement = this.acknowledgment val newAcknowledgement = newLogbookMessageAcknowledgement.message as Acknowledgment @@ -164,46 +139,6 @@ data class LogbookMessage( } } - private fun enrichAcnkowledge(relatedLogbookMessages: List) { - if (this.transmissionFormat == LogbookTransmissionFormat.FLUX || - LogbookSoftware.isVisioCapture(software) - ) { - this.setAcknowledgeAsSuccessful() - - return - } - - val historycallyOrderedRetLogbookMessages = relatedLogbookMessages - .filter { it.operationType == LogbookOperationType.RET && it.referencedReportId == reportId } - .sortedBy { it.reportDateTime } - - val maybeLastSuccessfulRetLogbookMessage = historycallyOrderedRetLogbookMessages.lastOrNull { - val message = it.message as Acknowledgment - - message.returnStatus == RETReturnErrorCode.SUCCESS.number - } - // If there is at least one successful RET message, we consider the report as acknowledged - if (maybeLastSuccessfulRetLogbookMessage != null) { - val lastSucessfulRetMessage = maybeLastSuccessfulRetLogbookMessage.message as Acknowledgment - this.acknowledgment = lastSucessfulRetMessage.also { - it.dateTime = maybeLastSuccessfulRetLogbookMessage.reportDateTime - it.isSuccess = true - } - - return - } - - // Else we consider the last (failure) RET message as the final acknowledgement - val maybeLastRetLogbookMessage = historycallyOrderedRetLogbookMessages.lastOrNull() - if (maybeLastRetLogbookMessage != null) { - val lastRetMessage = maybeLastRetLogbookMessage.message as Acknowledgment - this.acknowledgment = lastRetMessage.also { - it.dateTime = maybeLastRetLogbookMessage.reportDateTime - it.isSuccess = lastRetMessage.returnStatus == RETReturnErrorCode.SUCCESS.number - } - } - } - private fun enrichAcknowledgeCorrectionAndDeletion(contextLogbookMessages: List) { val referenceLogbookMessage = findReferencedLogbookMessage(contextLogbookMessages) val relatedLogbookMessages = filterRelatedLogbookMessages(contextLogbookMessages) @@ -226,7 +161,7 @@ data class LogbookMessage( (transmissionFormat == LogbookTransmissionFormat.FLUX), (LogbookSoftware.isVisioCapture(software)), - -> { + -> { setAcknowledgeAsSuccessful() } From 40eee0b8a5e414a9d9dee6fd5872828683ed6e5e Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 15:16:18 +0200 Subject: [PATCH 09/26] Add chain resolution in JpaLogbookReportRepository.findPriorNotificationByReportId() --- .../domain/entities/logbook/LogbookMessage.kt | 2 +- .../JpaLogbookReportRepository.kt | 92 +++++++++---------- .../interfaces/DBLogbookReportRepository.kt | 2 +- 3 files changed, 44 insertions(+), 52 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt index fd2b6c7c22..44a135c147 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt @@ -161,7 +161,7 @@ data class LogbookMessage( (transmissionFormat == LogbookTransmissionFormat.FLUX), (LogbookSoftware.isVisioCapture(software)), - -> { + -> { setAcknowledgeAsSuccessful() } diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 9754b00ded..64c5cf56c9 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -19,7 +19,6 @@ import fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.interfaces. import fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.utils.toSqlArrayString import fr.gouv.cnsp.monitorfish.utils.CustomZonedDateTime import jakarta.transaction.Transactional -import org.slf4j.LoggerFactory import org.springframework.cache.annotation.CacheEvict import org.springframework.cache.annotation.Cacheable import org.springframework.dao.EmptyResultDataAccessException @@ -34,8 +33,6 @@ class JpaLogbookReportRepository( private val dbLogbookReportRepository: DBLogbookReportRepository, private val objectMapper: ObjectMapper, ) : LogbookReportRepository { - private val logger = LoggerFactory.getLogger(JpaLogbookReportRepository::class.java) - override fun findAllPriorNotifications(filter: PriorNotificationsFilter): List { // Acknowledged "DAT", "COR" and "DEL" operations val logbookReportModelsWithCorAndDel = @@ -83,12 +80,25 @@ class JpaLogbookReportRepository( } override fun findPriorNotificationByReportId(reportId: String, operationDate: ZonedDateTime): PriorNotification? { - val logbookReportModel = dbLogbookReportRepository.findByReportId( + val logbookReportModelsWithCorAndDel = dbLogbookReportRepository.findByReportId( reportId, operationDate.toString(), ) + val datOrOrphanCorLogbooReportModel = logbookReportModelsWithCorAndDel.firstOrNull { + it.operationType == LogbookOperationType.DAT || ( + it.operationType == LogbookOperationType.COR && + logbookReportModelsWithCorAndDel.none { model -> model.reportId == it.referencedReportId } + ) + } + if (datOrOrphanCorLogbooReportModel == null) { + return null + } - return logbookReportModel?.toPriorNotification(objectMapper) + return resolveAsPriorNotification( + datOrOrphanCorLogbooReportModel, + logbookReportModelsWithCorAndDel, + objectMapper, + ) } override fun findLastTripBeforeDateTime( @@ -334,22 +344,15 @@ class JpaLogbookReportRepository( isSent: Boolean, isVerified: Boolean, ): PriorNotification { - val logbookReportModel = - dbLogbookReportRepository.findByReportId( - reportId, - operationDate.withZoneSameInstant(UTC).toString(), - ) - if (logbookReportModel == null) { - throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - } + val priorNotification = findPriorNotificationByReportId(reportId, operationDate) + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) - pnoMessage.isBeingSent = isBeingSent - pnoMessage.isSent = isSent - pnoMessage.isVerified = isVerified - - val nextMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedModel = logbookReportModel.copy(message = nextMessage) + val nextPnoMessage = priorNotification.logbookMessageAndValue.value + nextPnoMessage.isBeingSent = isBeingSent + nextPnoMessage.isSent = isSent + nextPnoMessage.isVerified = isVerified + val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) + val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) return dbLogbookReportRepository.save(updatedModel).toPriorNotification(objectMapper) } @@ -362,36 +365,30 @@ class JpaLogbookReportRepository( authorTrigram: String?, note: String?, ) { - val logbookReportModel = - dbLogbookReportRepository.findByReportId( - reportId, - operationDate.withZoneSameInstant(UTC).toString(), - ) - if (logbookReportModel == null) { - throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - } + val priorNotification = findPriorNotificationByReportId(reportId, operationDate) + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + val nextPnoMessage = priorNotification.logbookMessageAndValue.value if ( - Utils.areStringsEqual(authorTrigram, pnoMessage.authorTrigram) && - Utils.areStringsEqual(note, pnoMessage.note) + Utils.areStringsEqual(authorTrigram, nextPnoMessage.authorTrigram) && + Utils.areStringsEqual(note, nextPnoMessage.note) ) { return } - pnoMessage.authorTrigram = authorTrigram - pnoMessage.note = note + nextPnoMessage.authorTrigram = authorTrigram + nextPnoMessage.note = note /** * The PNO states are re-initialized: * - the PDF will be re-generated (done in the use case by deleting the old one) * - the PNO will require another verification before sending */ - pnoMessage.isBeingSent = false - pnoMessage.isSent = false - pnoMessage.isVerified = false + nextPnoMessage.isBeingSent = false + nextPnoMessage.isSent = false + nextPnoMessage.isVerified = false - val nextMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedModel = logbookReportModel.copy(message = nextMessage) + val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) + val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) dbLogbookReportRepository.save(updatedModel) } @@ -399,21 +396,16 @@ class JpaLogbookReportRepository( @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val logbookReportModel = dbLogbookReportRepository.findByReportId( - reportId, - operationDate.withZoneSameInstant(UTC).toString(), - ) - if (logbookReportModel == null) { - throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - } + val priorNotification = findPriorNotificationByReportId(reportId, operationDate) + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) - pnoMessage.isInvalidated = true + val nextPnoMessage = priorNotification.logbookMessageAndValue.value + nextPnoMessage.isInvalidated = true - val nextMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedEntity = logbookReportModel.copy(message = nextMessage) + val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) + val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) - dbLogbookReportRepository.save(updatedEntity) + dbLogbookReportRepository.save(updatedModel) } private fun getAllMessagesExceptionMessage(internalReferenceNumber: String) = diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index ff788b1ed7..f71ff71722 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -265,7 +265,7 @@ interface DBLogbookReportRepository : fun findByReportId( reportId: String, operationDate: String, - ): LogbookReportEntity? + ): List @Query( """SELECT new fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.interfaces.VoyageTripNumberAndDate(e.tripNumber, MIN(e.operationDateTime)) From 76e29e40fbd0c30f1eb10928747ee9591f1c6b5b Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 15:30:05 +0200 Subject: [PATCH 10/26] Clarify naming in JpaLogbookReportRepository --- .../repositories/LogbookReportRepository.kt | 4 +- .../GetPriorNotification.kt | 3 +- .../GetPriorNotifications.kt | 2 +- .../JpaLogbookReportRepository.kt | 34 +++++++++-------- .../GetPriorNotificationUTests.kt | 4 +- .../GetPriorNotificationsUTests.kt | 2 +- .../VerifyAndSendPriorNotificationUTests.kt | 4 +- .../JpaLogbookReportRepositoryITests.kt | 38 +++++++++---------- 8 files changed, 48 insertions(+), 43 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt index afc2477ec8..3d34814cdf 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt @@ -10,7 +10,7 @@ import fr.gouv.cnsp.monitorfish.domain.exceptions.NoLogbookFishingTripFound import java.time.ZonedDateTime interface LogbookReportRepository { - fun findAllPriorNotifications(filter: PriorNotificationsFilter): List + fun findAllAcknowledgedPriorNotifications(filter: PriorNotificationsFilter): List @Throws(NoLogbookFishingTripFound::class) fun findLastTripBeforeDateTime( @@ -46,7 +46,7 @@ interface LogbookReportRepository { // Only used in tests fun findById(id: Long): LogbookMessage - fun findPriorNotificationByReportId(reportId: String, operationDate: ZonedDateTime): PriorNotification? + fun findAcknowledgedPriorNotificationByReportId(reportId: String, operationDate: ZonedDateTime): PriorNotification? fun findLastMessageDate(): ZonedDateTime diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotification.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotification.kt index 30aba7b34a..1577a276e7 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotification.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotification.kt @@ -29,7 +29,7 @@ class GetPriorNotification( val priorNotification = if (isManuallyCreated) { manualPriorNotificationRepository.findByReportId(reportId) } else { - logbookReportRepository.findPriorNotificationByReportId(reportId, operationDate) + logbookReportRepository.findAcknowledgedPriorNotificationByReportId(reportId, operationDate) } ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) @@ -55,6 +55,7 @@ class GetPriorNotification( } else { null } + false -> if (priorNotification.logbookMessageAndValue.logbookMessage.internalReferenceNumber != null) { vesselRepository.findFirstByInternalReferenceNumber( priorNotification.logbookMessageAndValue.logbookMessage.internalReferenceNumber!!, diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt index 5e04c42b9f..a4c57cc918 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt @@ -43,7 +43,7 @@ class GetPriorNotifications( val allSpecies = speciesRepository.findAll() val (automaticPriorNotifications, findAllPriorNotificationsTimeTaken) = measureTimedValue { - logbookReportRepository.findAllPriorNotifications(filter) + logbookReportRepository.findAllAcknowledgedPriorNotifications(filter) } logger.info( "TIME_RECORD - 'logbookReportRepository.findAllPriorNotifications()' took $findAllPriorNotificationsTimeTaken.", diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 64c5cf56c9..f3839c5146 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -33,7 +33,7 @@ class JpaLogbookReportRepository( private val dbLogbookReportRepository: DBLogbookReportRepository, private val objectMapper: ObjectMapper, ) : LogbookReportRepository { - override fun findAllPriorNotifications(filter: PriorNotificationsFilter): List { + override fun findAllAcknowledgedPriorNotifications(filter: PriorNotificationsFilter): List { // Acknowledged "DAT", "COR" and "DEL" operations val logbookReportModelsWithCorAndDel = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( @@ -72,31 +72,35 @@ class JpaLogbookReportRepository( willArriveBefore = CustomZonedDateTime(ZonedDateTime.now().plusHours(24)).toString(), ) - return findAllPriorNotifications(filter).filter { + return findAllAcknowledgedPriorNotifications(filter).filter { it.logbookMessageAndValue.value.isInVerificationScope == true && it.logbookMessageAndValue.value.isVerified == false && it.logbookMessageAndValue.value.isInvalidated != true } } - override fun findPriorNotificationByReportId(reportId: String, operationDate: ZonedDateTime): PriorNotification? { - val logbookReportModelsWithCorAndDel = dbLogbookReportRepository.findByReportId( - reportId, - operationDate.toString(), - ) - val datOrOrphanCorLogbooReportModel = logbookReportModelsWithCorAndDel.firstOrNull { + /** + * Return null if the logbook report is deleted by an aknowledged "DEL" operation. + */ + override fun findAcknowledgedPriorNotificationByReportId( + reportId: String, + operationDate: ZonedDateTime, + ): PriorNotification? { + // Acknowledged "DAT" and "COR" operations + val logbookReportModelsWithCor = dbLogbookReportRepository.findByReportId(reportId, operationDate.toString()) + val datOrOrphanCorLogbookReportModel = logbookReportModelsWithCor.firstOrNull { it.operationType == LogbookOperationType.DAT || ( it.operationType == LogbookOperationType.COR && - logbookReportModelsWithCorAndDel.none { model -> model.reportId == it.referencedReportId } + logbookReportModelsWithCor.none { model -> model.reportId == it.referencedReportId } ) } - if (datOrOrphanCorLogbooReportModel == null) { + if (datOrOrphanCorLogbookReportModel == null) { return null } return resolveAsPriorNotification( - datOrOrphanCorLogbooReportModel, - logbookReportModelsWithCorAndDel, + datOrOrphanCorLogbookReportModel, + logbookReportModelsWithCor, objectMapper, ) } @@ -344,7 +348,7 @@ class JpaLogbookReportRepository( isSent: Boolean, isVerified: Boolean, ): PriorNotification { - val priorNotification = findPriorNotificationByReportId(reportId, operationDate) + val priorNotification = findAcknowledgedPriorNotificationByReportId(reportId, operationDate) ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val nextPnoMessage = priorNotification.logbookMessageAndValue.value @@ -365,7 +369,7 @@ class JpaLogbookReportRepository( authorTrigram: String?, note: String?, ) { - val priorNotification = findPriorNotificationByReportId(reportId, operationDate) + val priorNotification = findAcknowledgedPriorNotificationByReportId(reportId, operationDate) ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val nextPnoMessage = priorNotification.logbookMessageAndValue.value @@ -396,7 +400,7 @@ class JpaLogbookReportRepository( @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val priorNotification = findPriorNotificationByReportId(reportId, operationDate) + val priorNotification = findAcknowledgedPriorNotificationByReportId(reportId, operationDate) ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val nextPnoMessage = priorNotification.logbookMessageAndValue.value diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationUTests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationUTests.kt index 1585ea8421..83813036b3 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationUTests.kt @@ -50,7 +50,7 @@ class GetPriorNotificationUTests { // Given given( - logbookReportRepository.findPriorNotificationByReportId( + logbookReportRepository.findAcknowledgedPriorNotificationByReportId( fakePriorNotification.reportId!!, fakePriorNotification.logbookMessageAndValue.logbookMessage.operationDateTime, ), @@ -108,7 +108,7 @@ class GetPriorNotificationUTests { // Given given( - logbookReportRepository.findPriorNotificationByReportId( + logbookReportRepository.findAcknowledgedPriorNotificationByReportId( fakeLogbookMessageReferenceReportId, fakePriorNotification.logbookMessageAndValue.logbookMessage.operationDateTime, ), diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationsUTests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationsUTests.kt index f3822d7632..55901ba4cd 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationsUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotificationsUTests.kt @@ -59,7 +59,7 @@ class GetPriorNotificationsUTests { @Test fun `execute Should return a list of prior notifications with their total length`() { // Given - given(logbookReportRepository.findAllPriorNotifications(defaultFilter)).willReturn( + given(logbookReportRepository.findAllAcknowledgedPriorNotifications(defaultFilter)).willReturn( listOf( PriorNotification( reportId = "FAKE_REPORT_ID_1", diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/VerifyAndSendPriorNotificationUTests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/VerifyAndSendPriorNotificationUTests.kt index 5b485eaf75..ae4ce40861 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/VerifyAndSendPriorNotificationUTests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/VerifyAndSendPriorNotificationUTests.kt @@ -27,7 +27,7 @@ class VerifyAndSendPriorNotificationUTests { // Given given( - logbookReportRepository.findPriorNotificationByReportId( + logbookReportRepository.findAcknowledgedPriorNotificationByReportId( fakePriorNotification.reportId!!, fakePriorNotification.logbookMessageAndValue.logbookMessage.operationDateTime, ), @@ -65,7 +65,7 @@ class VerifyAndSendPriorNotificationUTests { // Given given( - logbookReportRepository.findPriorNotificationByReportId( + logbookReportRepository.findAcknowledgedPriorNotificationByReportId( fakePriorNotification.reportId!!, fakePriorNotification.logbookMessageAndValue.logbookMessage.operationDateTime, ), diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt index effbf988ab..21d85bcbc8 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepositoryITests.kt @@ -549,7 +549,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) @@ -575,7 +575,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val firstResult = jpaLogbookReportRepository.findAllPriorNotifications(firstFilter) + val firstResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(firstFilter) // Then assertThat(firstResult).hasSizeGreaterThan(0) @@ -593,7 +593,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val secondResult = jpaLogbookReportRepository.findAllPriorNotifications(secondFilter) + val secondResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(secondFilter) // Then assertThat(secondResult).hasSizeGreaterThan(0) @@ -615,7 +615,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val firstResult = jpaLogbookReportRepository.findAllPriorNotifications(firstFilter) + val firstResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(firstFilter) // Then assertThat(firstResult).hasSizeGreaterThan(0) @@ -635,7 +635,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val secondResult = jpaLogbookReportRepository.findAllPriorNotifications(secondFilter) + val secondResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(secondFilter) // Then assertThat(secondResult).hasSizeGreaterThan(0) @@ -659,7 +659,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val firstResult = jpaLogbookReportRepository.findAllPriorNotifications(firstFilter) + val firstResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(firstFilter) // Then assertThat(firstResult).hasSizeGreaterThan(0) @@ -683,7 +683,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val secondResult = jpaLogbookReportRepository.findAllPriorNotifications(secondFilter) + val secondResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(secondFilter) // Then assertThat(secondResult).hasSizeGreaterThan(0) @@ -711,7 +711,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) @@ -733,7 +733,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val firstResult = jpaLogbookReportRepository.findAllPriorNotifications(firstFilter) + val firstResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(firstFilter) // Then assertThat(firstResult).hasSizeGreaterThan(0) @@ -753,7 +753,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val secondResult = jpaLogbookReportRepository.findAllPriorNotifications(secondFilter) + val secondResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(secondFilter) // Then assertThat(secondResult).hasSizeGreaterThan(0) @@ -777,7 +777,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val firstResult = jpaLogbookReportRepository.findAllPriorNotifications(firstFilter) + val firstResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(firstFilter) // Then assertThat(firstResult).hasSizeGreaterThan(0) @@ -797,7 +797,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val secondResult = jpaLogbookReportRepository.findAllPriorNotifications(secondFilter) + val secondResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(secondFilter) // Then assertThat(secondResult).hasSizeGreaterThan(0) @@ -821,7 +821,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) @@ -844,7 +844,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) @@ -867,7 +867,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) @@ -894,7 +894,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) @@ -916,7 +916,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val firstResult = jpaLogbookReportRepository.findAllPriorNotifications(firstFilter) + val firstResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(firstFilter) // Then assertThat(firstResult).hasSizeGreaterThan(0) @@ -934,7 +934,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val secondResult = jpaLogbookReportRepository.findAllPriorNotifications(secondFilter) + val secondResult = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(secondFilter) // Then assertThat(secondResult).hasSizeGreaterThan(0) @@ -958,7 +958,7 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() { ) // When - val result = jpaLogbookReportRepository.findAllPriorNotifications(filter) + val result = jpaLogbookReportRepository.findAllAcknowledgedPriorNotifications(filter) // Then assertThat(result).hasSizeGreaterThan(0) From 68a414ba339db9008572002a6c778b794255b5eb Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 16:45:26 +0200 Subject: [PATCH 11/26] Fix prior notification list reportIds in Backend --- .../domain/entities/logbook/LogbookMessage.kt | 7 --- .../prior_notification/PriorNotification.kt | 27 +++++++++++ .../PriorNotificationDetailDataOutput.kt | 10 ++-- .../PriorNotificationListItemDataOutput.kt | 13 +++-- .../database/entities/LogbookReportEntity.kt | 31 ------------ .../JpaLogbookReportRepository.kt | 47 ++++++++++++------- 6 files changed, 70 insertions(+), 65 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt index 44a135c147..b8e947625c 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/logbook/LogbookMessage.kt @@ -43,13 +43,6 @@ data class LogbookMessage( ) { private val logger = LoggerFactory.getLogger(LogbookMessage::class.java) - /** - * Returns the reference logbook message `reportId` (= the original DAT operation `reportId`). - */ - fun getReferenceReportId(): String? { - return referencedReportId ?: reportId - } - fun setAcknowledge(newLogbookMessageAcknowledgement: LogbookMessage) { val currentAcknowledgement = this.acknowledgment val newAcknowledgement = newLogbookMessageAcknowledgement.message as Acknowledgment diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt index 864413ff46..febd369fd4 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt @@ -2,6 +2,7 @@ package fr.gouv.cnsp.monitorfish.domain.entities.prior_notification import fr.gouv.cnsp.monitorfish.domain.entities.facade.Seafront import fr.gouv.cnsp.monitorfish.domain.entities.gear.Gear +import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessage import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessageAndValue import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.Acknowledgment import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO @@ -10,6 +11,7 @@ import fr.gouv.cnsp.monitorfish.domain.entities.reporting.ReportingType import fr.gouv.cnsp.monitorfish.domain.entities.reporting.filters.ReportingFilter import fr.gouv.cnsp.monitorfish.domain.entities.risk_factor.VesselRiskFactor import fr.gouv.cnsp.monitorfish.domain.entities.species.Species +import fr.gouv.cnsp.monitorfish.domain.entities.vessel.UNKNOWN_VESSEL import fr.gouv.cnsp.monitorfish.domain.entities.vessel.Vessel import fr.gouv.cnsp.monitorfish.domain.exceptions.BackendInternalErrorCode import fr.gouv.cnsp.monitorfish.domain.exceptions.NoERSMessagesFound @@ -154,6 +156,31 @@ data class PriorNotification( companion object { private val logger = LoggerFactory.getLogger(PriorNotification::class.java) + fun fromLogbookMessage(logbookMessage: LogbookMessage): PriorNotification { + val logbookMessageAndValue = LogbookMessageAndValue( + logbookMessage = logbookMessage, + clazz = PNO::class.java, + ) + + return PriorNotification( + reportId = logbookMessage.reportId, + createdAt = logbookMessage.operationDateTime, + didNotFishAfterZeroNotice = false, + isManuallyCreated = false, + logbookMessageAndValue = logbookMessageAndValue, + sentAt = logbookMessageAndValue.logbookMessage.reportDateTime, + updatedAt = logbookMessage.operationDateTime, + + // These props need to be calculated in the use case + port = null, + reportingCount = null, + seafront = null, + // For practical reasons `vessel` can't be `null`, so we temporarily set it to "Navire inconnu" + vessel = UNKNOWN_VESSEL, + lastControlDateTime = null, + ) + } + /** * Next initial state of the prior notification once it will be created or updated. * diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationDetailDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationDetailDataOutput.kt index 206d5d5847..f4c6eef0ae 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationDetailDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationDetailDataOutput.kt @@ -19,6 +19,10 @@ class PriorNotificationDetailDataOutput( ) { companion object { fun fromPriorNotification(priorNotification: PriorNotification): PriorNotificationDetailDataOutput { + val reportId = requireNotNull(priorNotification.reportId) { + "`reportId` is null." + } + val isLessThanTwelveMetersVessel = requireNotNull(priorNotification.vessel) { "`priorNotification.vessel` is null." }.isLessThanTwelveMetersVessel() @@ -26,13 +30,11 @@ class PriorNotificationDetailDataOutput( "`priorNotification.vessel` is null." }.underCharter val logbookMessage = priorNotification.logbookMessageAndValue.logbookMessage - val referenceReportId = requireNotNull(logbookMessage.getReferenceReportId()) { - "`logbookMessage.getReferenceReportId()` returned null." - } + val logbookMessageDataOutput = LogbookMessageDataOutput.fromLogbookMessage(logbookMessage) return PriorNotificationDetailDataOutput( - reportId = referenceReportId, + reportId, fingerprint = priorNotification.fingerprint, isLessThanTwelveMetersVessel = isLessThanTwelveMetersVessel, isManuallyCreated = priorNotification.isManuallyCreated, diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationListItemDataOutput.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationListItemDataOutput.kt index 7f78e74564..f6c2a6debe 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationListItemDataOutput.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/outputs/PriorNotificationListItemDataOutput.kt @@ -10,8 +10,7 @@ import org.slf4j.LoggerFactory import java.time.ZonedDateTime data class PriorNotificationListItemDataOutput( - /** Reference logbook message (report) `reportId`. */ - val id: String, + val reportId: String, val acknowledgment: AcknowledgmentDataOutput?, val createdAt: ZonedDateTime?, val expectedArrivalDate: ZonedDateTime?, @@ -51,13 +50,13 @@ data class PriorNotificationListItemDataOutput( val logger: Logger = LoggerFactory.getLogger(PriorNotificationListItemDataOutput::class.java) fun fromPriorNotification(priorNotification: PriorNotification): PriorNotificationListItemDataOutput? { - val logbookMessage = priorNotification.logbookMessageAndValue.logbookMessage - val referenceReportId = logbookMessage.getReferenceReportId() - if (referenceReportId == null) { - logger.warn("Prior notification has neither `reportId` nor `referencedReportId`: $priorNotification.") + if (priorNotification.reportId == null) { + logger.warn("Prior notification has no `reportId`: $priorNotification.") return null } + + val logbookMessage = priorNotification.logbookMessageAndValue.logbookMessage val message = priorNotification.logbookMessageAndValue.value val acknowledgment = logbookMessage.acknowledgment?.let { AcknowledgmentDataOutput.fromAcknowledgment(it) } @@ -73,7 +72,7 @@ data class PriorNotificationListItemDataOutput( val vessel = requireNotNull(priorNotification.vessel) { "`vessel` is null." } return PriorNotificationListItemDataOutput( - id = referenceReportId, + reportId = priorNotification.reportId, acknowledgment = acknowledgment, createdAt = priorNotification.createdAt, expectedArrivalDate = message.predictedArrivalDatetimeUtc, diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt index 82571a8baf..7a39b334a3 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/entities/LogbookReportEntity.kt @@ -2,9 +2,6 @@ package fr.gouv.cnsp.monitorfish.infrastructure.database.entities import com.fasterxml.jackson.databind.ObjectMapper import fr.gouv.cnsp.monitorfish.domain.entities.logbook.* -import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO -import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotification -import fr.gouv.cnsp.monitorfish.domain.entities.vessel.UNKNOWN_VESSEL import fr.gouv.cnsp.monitorfish.domain.mappers.ERSMapper.getERSMessageValueFromJSON import io.hypersistence.utils.hibernate.type.json.JsonBinaryType import jakarta.persistence.* @@ -140,34 +137,6 @@ data class LogbookReportEntity( ) } - fun toPriorNotification(mapper: ObjectMapper): PriorNotification { - val logbookMessage = toLogbookMessage(mapper) - val logbookMessageAndValue = LogbookMessageAndValue( - logbookMessage = logbookMessage, - clazz = PNO::class.java, - ) - val updatedAt = operationDateTime.atZone(UTC) - // For practical reasons `vessel` can't be `null`, so we temporarily set it to "Navire inconnu" - val vessel = UNKNOWN_VESSEL - - return PriorNotification( - reportId = reportId, - createdAt = operationDateTime.atZone(UTC), - didNotFishAfterZeroNotice = false, - isManuallyCreated = false, - logbookMessageAndValue = logbookMessageAndValue, - sentAt = logbookMessageAndValue.logbookMessage.reportDateTime, - updatedAt = updatedAt, - - // These props need to be calculated in the use case - port = null, - reportingCount = null, - seafront = null, - vessel = vessel, - lastControlDateTime = null, - ) - } - private fun deserializeJSONList( mapper: ObjectMapper, json: String?, diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index f3839c5146..4cd42a1447 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -333,9 +333,11 @@ class JpaLogbookReportRepository( @Modifying @Transactional override fun savePriorNotification(logbookMessageAndValue: LogbookMessageAndValue): PriorNotification { - return dbLogbookReportRepository - .save(LogbookReportEntity.fromLogbookMessage(objectMapper, logbookMessageAndValue.logbookMessage)) - .toPriorNotification(objectMapper) + return PriorNotification.fromLogbookMessage( + dbLogbookReportRepository + .save(LogbookReportEntity.fromLogbookMessage(objectMapper, logbookMessageAndValue.logbookMessage)) + .toLogbookMessage(objectMapper), + ) } @Transactional @@ -358,7 +360,9 @@ class JpaLogbookReportRepository( val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) - return dbLogbookReportRepository.save(updatedModel).toPriorNotification(objectMapper) + return PriorNotification.fromLogbookMessage( + dbLogbookReportRepository.save(updatedModel).toLogbookMessage(objectMapper), + ) } @Transactional @@ -422,21 +426,32 @@ class JpaLogbookReportRepository( objectMapper: ObjectMapper, ): PriorNotification { val child = list.find { it.referencedReportId == parent.reportId } - if (child?.reportId == null) { - val datOrCorParent = parent.toPriorNotification(objectMapper) - datOrCorParent.markAsAcknowledged() - return datOrCorParent - } - if (child.operationType == LogbookOperationType.DEL) { - val delParent = parent.toPriorNotification(objectMapper) - delParent.markAsAcknowledged() - delParent.markAsDeleted() + return when { + child?.operationType == LogbookOperationType.DEL -> { + val deletedParent = PriorNotification.fromLogbookMessage(parent.toLogbookMessage(objectMapper)) + deletedParent.markAsAcknowledged() + deletedParent.markAsDeleted() - return delParent - } + deletedParent + } + + child?.reportId == null && child?.operationType == LogbookOperationType.COR -> { + val corChild = PriorNotification.fromLogbookMessage(child.toLogbookMessage(objectMapper)) + corChild.markAsAcknowledged() - return resolveAsPriorNotification(child, list, objectMapper) + corChild + } + + child?.reportId == null -> { + val datOrCorParent = PriorNotification.fromLogbookMessage(parent.toLogbookMessage(objectMapper)) + datOrCorParent.markAsAcknowledged() + + datOrCorParent + } + + else -> resolveAsPriorNotification(child, list, objectMapper) + } } } } From 9390ca2341321e46885b5fc46734bb5460d3d700 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 16:46:48 +0200 Subject: [PATCH 12/26] Comment duplicate vessel CFR test data case --- .../V666.2.1__Insert_more_dummy_vessels.sql | 2 -- .../V666.2.1__Insert_more_dummy_vessels.jsonc | 23 ++++++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/backend/src/main/resources/db/testdata/V666.2.1__Insert_more_dummy_vessels.sql b/backend/src/main/resources/db/testdata/V666.2.1__Insert_more_dummy_vessels.sql index 8baa4fa623..959ae227e7 100644 --- a/backend/src/main/resources/db/testdata/V666.2.1__Insert_more_dummy_vessels.sql +++ b/backend/src/main/resources/db/testdata/V666.2.1__Insert_more_dummy_vessels.sql @@ -19,8 +19,6 @@ INSERT INTO vessels (id, cfr, mmsi, ircs, external_immatriculation, vessel_name, INSERT INTO vessels (id, cfr, mmsi, ircs, external_immatriculation, vessel_name, flag_state, length, under_charter) VALUES (109, 'CFR109', 'MMSI109', 'IRCS109', 'EXTIMM109', 'LE POISSON D''AVRIL', 'FR', 25, false); -INSERT INTO vessels (id, cfr, mmsi, ircs, external_immatriculation, vessel_name, flag_state, length, under_charter) VALUES (1109, 'CFR109', 'MMSI109_DUPLICATE', 'IRCS109_DUPLICATE', 'EXTIMM109_DUPLICATE', 'LE POISSON D''AVRIL DUPLIQUÉ', 'FR', 50, true); - INSERT INTO vessels (id, cfr, mmsi, ircs, external_immatriculation, vessel_name, flag_state, length, under_charter) VALUES (110, 'CFR110', 'MMSI110', 'IRCS110', 'EXTIMM110', 'LA MER À BOIRE', 'FR', 12.5, false); INSERT INTO vessels (id, cfr, mmsi, ircs, external_immatriculation, vessel_name, flag_state, length, under_charter) VALUES (111, 'CFR111', 'MMSI111', 'IRCS111', 'EXTIMM111', 'LE MARIN D''EAU DOUCE', 'FR', 9.5, false); diff --git a/backend/src/main/resources/db/testdata/json/V666.2.1__Insert_more_dummy_vessels.jsonc b/backend/src/main/resources/db/testdata/json/V666.2.1__Insert_more_dummy_vessels.jsonc index 3085b42dd4..7c989ab746 100644 --- a/backend/src/main/resources/db/testdata/json/V666.2.1__Insert_more_dummy_vessels.jsonc +++ b/backend/src/main/resources/db/testdata/json/V666.2.1__Insert_more_dummy_vessels.jsonc @@ -125,17 +125,18 @@ "length": 25, "under_charter": false }, - { - "id": 1109, - "cfr": "CFR109", - "mmsi": "MMSI109_DUPLICATE", - "ircs": "IRCS109_DUPLICATE", - "external_immatriculation": "EXTIMM109_DUPLICATE", - "vessel_name": "LE POISSON D'AVRIL DUPLIQUÉ", - "flag_state": "FR", - "length": 50, - "under_charter": true - }, + // TODO Check that with Vincent, this breaks the prior notifications SQL query. + // { + // "id": 1109, + // "cfr": "CFR109", + // "mmsi": "MMSI109_DUPLICATE", + // "ircs": "IRCS109_DUPLICATE", + // "external_immatriculation": "EXTIMM109_DUPLICATE", + // "vessel_name": "LE POISSON D'AVRIL DUPLIQUÉ", + // "flag_state": "FR", + // "length": 50, + // "under_charter": true + // }, // - Vessel: LA MER À BOIRE { From fb996fa448f1dc2d3e510649448c292569d1233a Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 16:47:20 +0200 Subject: [PATCH 13/26] Rename prior notification list item id to report id in Frontend --- frontend/src/api/BackendApi.types.ts | 4 ++-- .../PriorNotification/PriorNotification.types.ts | 3 +-- .../components/PriorNotificationList/Row.tsx | 8 +++----- .../cells/ActionButtonsCell.tsx | 13 ++++--------- .../components/PriorNotificationList/columns.tsx | 4 ++-- .../components/PriorNotificationList/index.tsx | 2 +- frontend/src/features/PriorNotification/utils.ts | 12 +++++++++++- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/frontend/src/api/BackendApi.types.ts b/frontend/src/api/BackendApi.types.ts index d8672f150c..6c7f28e9c9 100644 --- a/frontend/src/api/BackendApi.types.ts +++ b/frontend/src/api/BackendApi.types.ts @@ -1,4 +1,4 @@ -import type { AnyEnum, CollectionItem } from '@mtes-mct/monitor-ui' +import type { AnyEnum } from '@mtes-mct/monitor-ui' import type { AnyObject } from 'yup' export namespace BackendApi { @@ -28,7 +28,7 @@ export namespace BackendApi { } export type ResponseBodyPaginatedList< - ItemData extends CollectionItem = CollectionItem, + ItemData extends AnyObject = AnyObject, ExtraData extends AnyObject | undefined = undefined > = { data: ItemData[] diff --git a/frontend/src/features/PriorNotification/PriorNotification.types.ts b/frontend/src/features/PriorNotification/PriorNotification.types.ts index 993b8b0130..c47184ca36 100644 --- a/frontend/src/features/PriorNotification/PriorNotification.types.ts +++ b/frontend/src/features/PriorNotification/PriorNotification.types.ts @@ -12,8 +12,6 @@ export namespace PriorNotification { /** Unique identifier concatenating all the DAT, COR, RET & DEL operations `id` used for data consolidation. */ fingerprint: string hasVesselRiskFactorSegments: boolean | undefined - /** Logbook message `reportId`. */ - id: string isBeingSent: boolean isCorrection: boolean isInVerificationScope: boolean @@ -27,6 +25,7 @@ export namespace PriorNotification { portLocode: string | undefined portName: string | undefined purposeCode: PurposeCode | undefined + reportId: string reportingCount: number riskFactor: number | undefined seafront: Seafront | undefined diff --git a/frontend/src/features/PriorNotification/components/PriorNotificationList/Row.tsx b/frontend/src/features/PriorNotification/components/PriorNotificationList/Row.tsx index df06a84c09..42bbd3cbbf 100644 --- a/frontend/src/features/PriorNotification/components/PriorNotificationList/Row.tsx +++ b/frontend/src/features/PriorNotification/components/PriorNotificationList/Row.tsx @@ -1,3 +1,4 @@ +import { getPriorNotificationIdentifier } from '@features/PriorNotification/utils' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { customDayjs, Icon, TableWithSelectableRows, Tag, THEME } from '@mtes-mct/monitor-ui' import { flexRender, type Row as RowType } from '@tanstack/react-table' @@ -25,7 +26,7 @@ export function Row({ row }: RowProps) { if (priorNotification.isManuallyCreated) { dispatch( openManualPriorNotificationForm( - { operationDate: priorNotification.operationDate, reportId: priorNotification.id }, + getPriorNotificationIdentifier(priorNotification), priorNotification.fingerprint ) ) @@ -35,10 +36,7 @@ export function Row({ row }: RowProps) { dispatch( openPriorNotificationCard( - { - operationDate: priorNotification.operationDate, - reportId: priorNotification.id - }, + getPriorNotificationIdentifier(priorNotification), priorNotification.fingerprint, priorNotification.isManuallyCreated ) diff --git a/frontend/src/features/PriorNotification/components/PriorNotificationList/cells/ActionButtonsCell.tsx b/frontend/src/features/PriorNotification/components/PriorNotificationList/cells/ActionButtonsCell.tsx index 37353eed66..518f90a303 100644 --- a/frontend/src/features/PriorNotification/components/PriorNotificationList/cells/ActionButtonsCell.tsx +++ b/frontend/src/features/PriorNotification/components/PriorNotificationList/cells/ActionButtonsCell.tsx @@ -1,5 +1,6 @@ import { openLogbookPriorNotificationForm } from '@features/PriorNotification/useCases/openLogbookPriorNotificationForm' import { openManualPriorNotificationForm } from '@features/PriorNotification/useCases/openManualPriorNotificationForm' +import { getPriorNotificationIdentifier } from '@features/PriorNotification/utils' import { useMainAppDispatch } from '@hooks/useMainAppDispatch' import { Accent, Icon, IconButton } from '@mtes-mct/monitor-ui' import { VesselIdentifier, type VesselIdentity } from 'domain/entities/vessel/types' @@ -22,7 +23,7 @@ export function ActionButtonsCell({ priorNotification }: ActionButtonsCellProps) if (priorNotification.isManuallyCreated) { dispatch( openManualPriorNotificationForm( - { operationDate: priorNotification.operationDate, reportId: priorNotification.id }, + getPriorNotificationIdentifier(priorNotification), priorNotification.fingerprint ) ) @@ -31,20 +32,14 @@ export function ActionButtonsCell({ priorNotification }: ActionButtonsCellProps) } dispatch( - openLogbookPriorNotificationForm( - { operationDate: priorNotification.operationDate, reportId: priorNotification.id }, - priorNotification.fingerprint - ) + openLogbookPriorNotificationForm(getPriorNotificationIdentifier(priorNotification), priorNotification.fingerprint) ) } const open = () => { dispatch( openPriorNotificationCard( - { - operationDate: priorNotification.operationDate, - reportId: priorNotification.id - }, + getPriorNotificationIdentifier(priorNotification), priorNotification.fingerprint, priorNotification.isManuallyCreated ) diff --git a/frontend/src/features/PriorNotification/components/PriorNotificationList/columns.tsx b/frontend/src/features/PriorNotification/components/PriorNotificationList/columns.tsx index ef2d3f249b..086def4a04 100644 --- a/frontend/src/features/PriorNotification/components/PriorNotificationList/columns.tsx +++ b/frontend/src/features/PriorNotification/components/PriorNotificationList/columns.tsx @@ -18,7 +18,7 @@ export function getTableColumns(isFromUrl: boolean): Array row.id, + accessorFn: row => row.reportId, cell: ({ row }) => ( row.id, + accessorFn: row => row.reportId, cell: (info: CellContext) => ( ), diff --git a/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx b/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx index a7ea953b90..60032d2c73 100644 --- a/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx +++ b/frontend/src/features/PriorNotification/components/PriorNotificationList/index.tsx @@ -122,7 +122,7 @@ export function PriorNotificationList({ isFromUrl }: PriorNotificationListProps) getCoreRowModel: getCoreRowModel(), getExpandedRowModel: getExpandedRowModel(), getRowCanExpand: () => true, - getRowId: row => row.id, + getRowId: row => row.reportId, manualPagination: true, manualSorting: true, onPaginationChange: setReactTablePaginationState, diff --git a/frontend/src/features/PriorNotification/utils.ts b/frontend/src/features/PriorNotification/utils.ts index bf70c8efa2..5cc2e24689 100644 --- a/frontend/src/features/PriorNotification/utils.ts +++ b/frontend/src/features/PriorNotification/utils.ts @@ -1,8 +1,18 @@ import type { PriorNotification } from './PriorNotification.types' import type { LogbookMessage } from '@features/Logbook/LogbookMessage.types' +type PriorNotificationData = { + operationDate: string + reportId: string +} + +export function getPriorNotificationIdentifier(data: PriorNotificationData): PriorNotification.Identifier +export function getPriorNotificationIdentifier(data: undefined): undefined +export function getPriorNotificationIdentifier( + data: PriorNotificationData | undefined +): PriorNotification.Identifier | undefined export function getPriorNotificationIdentifier( - data: { [key: string]: any; operationDate: string; reportId: string } | undefined + data: PriorNotificationData | undefined ): PriorNotification.Identifier | undefined { if (!data) { return undefined From 59dd6e6db44cd296ed64b7d26b84fd8df1ebc5f0 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 17:14:02 +0200 Subject: [PATCH 14/26] Remove non-acknowldged prior notification e2e test case --- .../error_handling.spec.ts | 4 +-- .../prior_notification_card/card.spec.ts | 29 ++++--------------- .../error_handling.spec.ts | 2 +- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/frontend/cypress/e2e/side_window/logbook_prior_notification_form/error_handling.spec.ts b/frontend/cypress/e2e/side_window/logbook_prior_notification_form/error_handling.spec.ts index 16c00cedf5..26100c5f9b 100644 --- a/frontend/cypress/e2e/side_window/logbook_prior_notification_form/error_handling.spec.ts +++ b/frontend/cypress/e2e/side_window/logbook_prior_notification_form/error_handling.spec.ts @@ -4,7 +4,7 @@ import { editSideWindowPriorNotification } from '../manual_prior_notification_fo context('Side Window > Logbook Prior Notification Form > Error Handling', () => { const failedQueryCount = RTK_MAX_RETRIES + 1 - const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109?isManuallyCreated=false&operationDate=*' + const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109_COR?isManuallyCreated=false&operationDate=*' it('Should handle fetching error as expected', () => { cy.intercept( @@ -18,7 +18,7 @@ context('Side Window > Logbook Prior Notification Form > Error Handling', () => } ).as('getPriorNotificationsWithError') - editSideWindowPriorNotification(`L'ANCRE`, 'FAKE_OPERATION_109') + editSideWindowPriorNotification(`L'ANCRE`, 'FAKE_OPERATION_109_COR') for (let i = 1; i <= failedQueryCount; i += 1) { cy.wait('@getPriorNotificationsWithError') diff --git a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts index 12e30851b9..5394da59fa 100644 --- a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts +++ b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts @@ -59,27 +59,8 @@ context('Side Window > Prior Notification Card > Card', () => { cy.contains(`25 kg`).should('be.visible') }) - it('Should display a failed acknowledged message as expected', () => { - openSideWindowPriorNotification(`CALAMARO`) - - // Title - cy.contains(`Préavis navire ≥ 12 M`).should('be.visible') - cy.contains(`CALAMARO (CFR105)`).should('be.visible') - - // Message Header - cy.contains(`PNO`).should('be.visible') - cy.contains(`Préavis (notification de retour au port)`).should('be.visible') - - // Message Body - cy.getDataCy('LogbookMessage-failed-acknowledgement-icon').should('be.visible') - cy.contains(`Saint-Malo (FRSML)`).should('be.visible') - cy.contains(`Débarquement (LAN)`).should('be.visible') - cy.contains(`BAUDROIE (ANF)`).should('be.visible') - cy.contains(`150 kg`).should('be.visible') - }) - it('Should refresh the list when the opened prior notification data differs from its entry in the current list', () => { - const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109?isManuallyCreated=false&operationDate=*' + const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109_COR?isManuallyCreated=false&operationDate=*' cy.intercept({ method: 'GET', @@ -112,7 +93,7 @@ context('Side Window > Prior Notification Card > Card', () => { }) it('Should display a warning banner and refresh the list when the opened prior notification has been deleted', () => { - const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109?isManuallyCreated=false&operationDate=*' + const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109_COR?isManuallyCreated=false&operationDate=*' cy.intercept({ method: 'GET', @@ -250,11 +231,11 @@ context('Side Window > Prior Notification Card > Card', () => { cy.get('[data-cy="side-window-sub-menu-ALL"]').click() cy.fill('Rechercher un navire', 'ANCRE') - cy.getTableRowById('FAKE_OPERATION_109' as any) + cy.getTableRowById('FAKE_OPERATION_109_COR' as any) .find('[title="Préavis invalidé"]') .should('not.exist') - cy.getTableRowById('FAKE_OPERATION_109' as any).clickButton('Éditer le préavis') + cy.getTableRowById('FAKE_OPERATION_109_COR' as any).clickButton('Éditer le préavis') if (document.querySelector('[data-cy="first-loader"]')) { cy.getDataCy('first-loader').should('not.be.visible') } @@ -269,7 +250,7 @@ context('Side Window > Prior Notification Card > Card', () => { cy.clickButton('Fermer') - cy.getTableRowById('FAKE_OPERATION_109' as any) + cy.getTableRowById('FAKE_OPERATION_109_COR' as any) .find('[title="Préavis invalidé"]') .should('exist') }) diff --git a/frontend/cypress/e2e/side_window/prior_notification_card/error_handling.spec.ts b/frontend/cypress/e2e/side_window/prior_notification_card/error_handling.spec.ts index 1c9e81c2a9..0250ec3fa4 100644 --- a/frontend/cypress/e2e/side_window/prior_notification_card/error_handling.spec.ts +++ b/frontend/cypress/e2e/side_window/prior_notification_card/error_handling.spec.ts @@ -4,7 +4,7 @@ import { openSideWindowPriorNotification } from './utils' context('Side Window > Logbook Prior Notification Card > Error Handling', () => { const failedQueryCount = RTK_MAX_RETRIES + 1 - const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109?isManuallyCreated=false&operationDate=*' + const url = '/bff/v1/prior_notifications/FAKE_OPERATION_109_COR?isManuallyCreated=false&operationDate=*' beforeEach(() => { cy.intercept('/bff/v1/authorization/current', { statusCode: 401 }).as('getIsSuperUser') From 007dd3bd44434edd91720406072ef6d2134e61d2 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 18:09:07 +0200 Subject: [PATCH 15/26] Fix logbook prior notification update in Backend --- .../repositories/LogbookReportRepository.kt | 2 +- .../JpaLogbookReportRepository.kt | 100 ++++++++++++------ 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt index 3d34814cdf..82f4671eac 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/repositories/LogbookReportRepository.kt @@ -73,7 +73,7 @@ interface LogbookReportRepository { isBeingSent: Boolean, isSent: Boolean, isVerified: Boolean, - ): PriorNotification + ) fun findAllPriorNotificationsToVerify(): List diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 4cd42a1447..754934d242 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -98,11 +98,7 @@ class JpaLogbookReportRepository( return null } - return resolveAsPriorNotification( - datOrOrphanCorLogbookReportModel, - logbookReportModelsWithCor, - objectMapper, - ) + return resolveAsPriorNotification(datOrOrphanCorLogbookReportModel, logbookReportModelsWithCor, objectMapper) } override fun findLastTripBeforeDateTime( @@ -349,20 +345,19 @@ class JpaLogbookReportRepository( isBeingSent: Boolean, isSent: Boolean, isVerified: Boolean, - ): PriorNotification { - val priorNotification = findAcknowledgedPriorNotificationByReportId(reportId, operationDate) + ) { + val logbookReportModel = findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate) ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val nextPnoMessage = priorNotification.logbookMessageAndValue.value - nextPnoMessage.isBeingSent = isBeingSent - nextPnoMessage.isSent = isSent - nextPnoMessage.isVerified = isVerified - val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) - val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) + val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + pnoMessage.isBeingSent = isBeingSent + pnoMessage.isSent = isSent + pnoMessage.isVerified = isVerified - return PriorNotification.fromLogbookMessage( - dbLogbookReportRepository.save(updatedModel).toLogbookMessage(objectMapper), - ) + val nextPnoMessage = objectMapper.writeValueAsString(pnoMessage) + val updatedModel = logbookReportModel.copy(message = nextPnoMessage) + + dbLogbookReportRepository.save(updatedModel) } @Transactional @@ -373,30 +368,30 @@ class JpaLogbookReportRepository( authorTrigram: String?, note: String?, ) { - val priorNotification = findAcknowledgedPriorNotificationByReportId(reportId, operationDate) + val logbookReportModel = findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate) ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val nextPnoMessage = priorNotification.logbookMessageAndValue.value + val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) if ( - Utils.areStringsEqual(authorTrigram, nextPnoMessage.authorTrigram) && - Utils.areStringsEqual(note, nextPnoMessage.note) + Utils.areStringsEqual(authorTrigram, pnoMessage.authorTrigram) && + Utils.areStringsEqual(note, pnoMessage.note) ) { return } - nextPnoMessage.authorTrigram = authorTrigram - nextPnoMessage.note = note + pnoMessage.authorTrigram = authorTrigram + pnoMessage.note = note /** * The PNO states are re-initialized: * - the PDF will be re-generated (done in the use case by deleting the old one) * - the PNO will require another verification before sending */ - nextPnoMessage.isBeingSent = false - nextPnoMessage.isSent = false - nextPnoMessage.isVerified = false + pnoMessage.isBeingSent = false + pnoMessage.isSent = false + pnoMessage.isVerified = false - val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) - val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) + val nextPnoMessage = objectMapper.writeValueAsString(pnoMessage) + val updatedModel = logbookReportModel.copy(message = nextPnoMessage) dbLogbookReportRepository.save(updatedModel) } @@ -404,22 +399,63 @@ class JpaLogbookReportRepository( @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val priorNotification = findAcknowledgedPriorNotificationByReportId(reportId, operationDate) + val logbookReportModel = findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate) ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val nextPnoMessage = priorNotification.logbookMessageAndValue.value - nextPnoMessage.isInvalidated = true + val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + pnoMessage.isInvalidated = true - val nextLogbookMessage = priorNotification.logbookMessageAndValue.logbookMessage.copy(message = nextPnoMessage) - val updatedModel = LogbookReportEntity.fromLogbookMessage(objectMapper, nextLogbookMessage) + val nextPnoMessage = objectMapper.writeValueAsString(pnoMessage) + val updatedModel = logbookReportModel.copy(message = nextPnoMessage) dbLogbookReportRepository.save(updatedModel) } + /** + * Return null if the logbook report is deleted by an aknowledged "DEL" operation. + */ + private fun findAcknowledgedPnoLogbookReportModelByReportId( + reportId: String, + operationDate: ZonedDateTime, + ): LogbookReportEntity? { + // Acknowledged "DAT" and "COR" operations + val logbookReportModelsWithCor = dbLogbookReportRepository.findByReportId(reportId, operationDate.toString()) + val datOrOrphanCorLogbookReportModel = logbookReportModelsWithCor.firstOrNull { + it.operationType == LogbookOperationType.DAT || ( + it.operationType == LogbookOperationType.COR && + logbookReportModelsWithCor.none { model -> model.reportId == it.referencedReportId } + ) + } + if (datOrOrphanCorLogbookReportModel == null) { + return null + } + + return resolveAsLogbookReportModel(datOrOrphanCorLogbookReportModel, logbookReportModelsWithCor) + } + private fun getAllMessagesExceptionMessage(internalReferenceNumber: String) = "No messages found for the vessel. (internalReferenceNumber: \"$internalReferenceNumber\")" companion object { + private fun resolveAsLogbookReportModel( + parent: LogbookReportEntity, + list: List, + ): LogbookReportEntity { + val child = list.find { it.referencedReportId == parent.reportId } + + return when { + child?.operationType == LogbookOperationType.COR -> { + child + } + + child?.reportId == null -> { + parent + } + + else -> resolveAsLogbookReportModel(child, list) + } + } + private fun resolveAsPriorNotification( parent: LogbookReportEntity, list: List, From 29f856a6cad7a6cb35f5c5c72396e09ceced8684 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 18:19:52 +0200 Subject: [PATCH 16/26] Fix e2e tests replacing non-acknowledged & right reportId --- .../prior_notification_card/card.spec.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts index 5394da59fa..5ed2179895 100644 --- a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts +++ b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts @@ -133,7 +133,7 @@ context('Side Window > Prior Notification Card > Card', () => { }) it('Should update a logbook prior notification', () => { - cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_108?operationDate=${dayjs().toISOString()}`, { + cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${dayjs().toISOString()}`, { body: { authorTrigram: null, note: null @@ -141,9 +141,9 @@ context('Side Window > Prior Notification Card > Card', () => { }) // Given - openSideWindowPriorNotification(`CALAMARO`) + openSideWindowPriorNotification(`MER À BOIRE`) - cy.intercept('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_108?operationDate=*`).as( + cy.intercept('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=*`).as( 'updateLogbookPriorNotification' ) @@ -160,13 +160,13 @@ context('Side Window > Prior Notification Card > Card', () => { cy.get('.Element-Button').contains('Télécharger').parent().should('be.disabled') // The note is saved - openSideWindowPriorNotification(`CALAMARO`) + openSideWindowPriorNotification(`MER À BOIRE`) cy.get('[name="note"]').should('have.value', "Un point d'attention.") cy.get('[name="authorTrigram"]').should('have.value', 'ABC') // Reset - cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_108?operationDate=${dayjs().toISOString()}`, { + cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${dayjs().toISOString()}`, { body: { authorTrigram: null, note: null @@ -179,7 +179,7 @@ context('Side Window > Prior Notification Card > Card', () => { cy.intercept( 'POST', - `/bff/v1/prior_notifications/FAKE_OPERATION_111/verify_and_send?isManuallyCreated=false&operationDate=*` + `/bff/v1/prior_notifications/FAKE_OPERATION_111_COR_ORPHAN/verify_and_send?isManuallyCreated=false&operationDate=*` ).as('verifyAndSendPriorNotification') cy.clickButton('Diffuser') @@ -203,7 +203,7 @@ context('Side Window > Prior Notification Card > Card', () => { cy.clickButton('Fermer') cy.fill('Rechercher un navire', 'LE POISSON AMBULANT') - cy.getTableRowById('FAKE_OPERATION_111' as unknown as number) + cy.getTableRowById('FAKE_OPERATION_111_COR_ORPHAN' as unknown as number) .find('span[title="Diffusion en cours"]') .should('be.visible') }) From 71845b3a4fb5df73aa91b35ecb696518b1b2a62e Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 18:56:18 +0200 Subject: [PATCH 17/26] Add dev commands for Cypress --- Makefile | 4 ++++ frontend/package.json | 1 + 2 files changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 79666b35e3..574d5c4758 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,10 @@ run-back: run-stubbed-apis docker compose up -d --quiet-pull --wait db keycloak cd backend && ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)' +run-back-for-cypress: run-stubbed-apis + docker compose up -d --quiet-pull --wait db keycloak + cd backend && MONITORFISH_OIDC_ENABLED=false ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)' + run-back-with-monitorenv: run-monitorenv docker compose up -d --quiet-pull --wait db cd backend && MONITORENV_URL=http://localhost:9880 ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)' diff --git a/frontend/package.json b/frontend/package.json index 2700242b8a..82928d88d2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,6 +13,7 @@ "clean": "rm -Rf ./node-modules/.vite ./node-modules/build", "cypress:open": "cypress open --browser firefox --config-file ./config/cypress.config.js --e2e", "dev": "import-meta-env-prepare -x ./.env.local.defaults && vite --port 3000", + "dev-cypress": "FRONTEND_OIDC_ENABLED=false import-meta-env-prepare -u -x ./.env.local.defaults && vite --port 3000", "dev-monitorenv": "FRONTEND_MONITORENV_URL=//localhost:9880 import-meta-env-prepare -u -x ./.env.local.defaults && vite --port 3000", "dev-puppeteer": "FRONTEND_MONITORENV_URL=//localhost:9880 import-meta-env-prepare -u -x ./.env.local.defaults && vite --port 3000", "bundle-sw": "esbuild src/workers/serviceWorker.ts --bundle --outfile=public/service-worker.js", From ef12e2c9722f0805c4d599a887c8d57dbefe5b9c Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 18:57:50 +0200 Subject: [PATCH 18/26] Restore missing UTC fix in JpaLogbookReportRepository --- .../repositories/JpaLogbookReportRepository.kt | 15 +++++++++------ .../api/bff/PriorNotificationControllerITests.kt | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 754934d242..1b7da5fbcd 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -346,8 +346,9 @@ class JpaLogbookReportRepository( isSent: Boolean, isVerified: Boolean, ) { - val logbookReportModel = findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate) - ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) + val logbookReportModel = + findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate.withZoneSameInstant(UTC)) + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) pnoMessage.isBeingSent = isBeingSent @@ -368,8 +369,9 @@ class JpaLogbookReportRepository( authorTrigram: String?, note: String?, ) { - val logbookReportModel = findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate) - ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) + val logbookReportModel = + findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate.withZoneSameInstant(UTC)) + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) if ( @@ -399,8 +401,9 @@ class JpaLogbookReportRepository( @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val logbookReportModel = findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate) - ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) + val logbookReportModel = + findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate.withZoneSameInstant(UTC)) + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) pnoMessage.isInvalidated = true diff --git a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/bff/PriorNotificationControllerITests.kt b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/bff/PriorNotificationControllerITests.kt index eea8b8bdb9..059d1c4438 100644 --- a/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/bff/PriorNotificationControllerITests.kt +++ b/backend/src/test/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/api/bff/PriorNotificationControllerITests.kt @@ -93,8 +93,8 @@ class PriorNotificationControllerITests { // Then .andExpect(status().isOk) .andExpect(jsonPath("$.data.length()", equalTo(2))) - .andExpect(jsonPath("$.data[0].id", equalTo(firstFakePriorNotification.reportId))) - .andExpect(jsonPath("$.data[1].id", equalTo(secondFakePriorNotification.reportId))) + .andExpect(jsonPath("$.data[0].reportId", equalTo(firstFakePriorNotification.reportId))) + .andExpect(jsonPath("$.data[1].reportId", equalTo(secondFakePriorNotification.reportId))) .andExpect(jsonPath("$.extraData.perSeafrontGroupCount", equalTo(emptyMap()))) .andExpect(jsonPath("$.lastPageNumber", equalTo(0))) .andExpect(jsonPath("$.pageNumber", equalTo(0))) From 7d7a0df5bf4cacdcb0f9456c39a3b526f496c110 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 19:27:22 +0200 Subject: [PATCH 19/26] Fix prior notification auto-save e2e test reset --- .../database/repositories/JpaLogbookReportRepository.kt | 7 +++++-- .../repositories/interfaces/DBLogbookReportRepository.kt | 2 +- .../logbook_prior_notification_form/form.spec.ts | 9 +++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 1b7da5fbcd..ec77baea34 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -87,7 +87,8 @@ class JpaLogbookReportRepository( operationDate: ZonedDateTime, ): PriorNotification? { // Acknowledged "DAT" and "COR" operations - val logbookReportModelsWithCor = dbLogbookReportRepository.findByReportId(reportId, operationDate.toString()) + val logbookReportModelsWithCor = dbLogbookReportRepository + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.toString()) val datOrOrphanCorLogbookReportModel = logbookReportModelsWithCor.firstOrNull { it.operationType == LogbookOperationType.DAT || ( it.operationType == LogbookOperationType.COR && @@ -422,7 +423,9 @@ class JpaLogbookReportRepository( operationDate: ZonedDateTime, ): LogbookReportEntity? { // Acknowledged "DAT" and "COR" operations - val logbookReportModelsWithCor = dbLogbookReportRepository.findByReportId(reportId, operationDate.toString()) + val logbookReportModelsWithCor = dbLogbookReportRepository + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.toString()) + logbookReportModelsWithCor.forEach { println("${it.reportId}") } val datOrOrphanCorLogbookReportModel = logbookReportModelsWithCor.firstOrNull { it.operationType == LogbookOperationType.DAT || ( it.operationType == LogbookOperationType.COR && diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index f71ff71722..992cdc4063 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -262,7 +262,7 @@ interface DBLogbookReportRepository : """, nativeQuery = true, ) - fun findByReportId( + fun findAcknowledgedNonDeletedPnoDatAndCorsByReportId( reportId: String, operationDate: String, ): List diff --git a/frontend/cypress/e2e/side_window/logbook_prior_notification_form/form.spec.ts b/frontend/cypress/e2e/side_window/logbook_prior_notification_form/form.spec.ts index be04b34384..d2e25145f0 100644 --- a/frontend/cypress/e2e/side_window/logbook_prior_notification_form/form.spec.ts +++ b/frontend/cypress/e2e/side_window/logbook_prior_notification_form/form.spec.ts @@ -4,11 +4,11 @@ import { editSideWindowPriorNotification } from '../manual_prior_notification_fo context('Side Window > Logbook Prior Notification Form > Form', () => { it('Should not update the form with a PUT request on first render', () => { - cy.intercept('PUT', '/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114*', cy.spy().as('updateForm')) + cy.intercept('PUT', '/bff/v1/prior_notifications/logbook/FAKE_OPERATION_115*', cy.spy().as('updateForm')) - editSideWindowPriorNotification(`LA MER À BOIRE`, 'FAKE_OPERATION_114') + editSideWindowPriorNotification(`LE MARIN`, 'FAKE_OPERATION_115') - cy.contains(`LA MER À BOIRE (CFR110)`).should('be.visible') + cy.contains(`LE MARIN D'EAU DOUCE (CFR111)`).should('be.visible') cy.get('@updateForm').should('not.have.been.called') @@ -17,7 +17,8 @@ context('Side Window > Logbook Prior Notification Form > Form', () => { cy.get('@updateForm').should('have.been.calledOnce') // Reset - cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${dayjs().toISOString()}`, { + const operationDate = dayjs().subtract(6, 'hours').toISOString() + cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_115?operationDate=${operationDate}`, { body: { authorTrigram: null, note: null From 86d802ff733966baf4dde4857e9ede9a03d82760 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 19:30:07 +0200 Subject: [PATCH 20/26] Fix prior notification update e2e test reset --- .../e2e/side_window/prior_notification_card/card.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts index 5ed2179895..fad87567fd 100644 --- a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts +++ b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts @@ -166,7 +166,8 @@ context('Side Window > Prior Notification Card > Card', () => { cy.get('[name="authorTrigram"]').should('have.value', 'ABC') // Reset - cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${dayjs().toISOString()}`, { + const operationDate = dayjs().subtract(6, 'hours').toISOString() + cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${operationDate}`, { body: { authorTrigram: null, note: null From e22c544e9a3e3cb1801969c32385a8a5d7916ebf Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 19:42:01 +0200 Subject: [PATCH 21/26] Restore VisioCapture value in logbook report test data --- .../db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql | 4 ++-- .../json/V666.5.1__Insert_more_pno_logbook_reports.jsonc | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql b/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql index d42b5edfec..4ae7710b6c 100644 --- a/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql +++ b/backend/src/main/resources/db/testdata/V666.5.1__Insert_more_pno_logbook_reports.sql @@ -69,12 +69,12 @@ INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_O INSERT INTO logbook_raw_messages (operation_number, xml_message) VALUES ('FAKE_OPERATION_115_RET', 'Message FLUX xml'); -INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (101, 'FAKE_OPERATION_101', NULL, 'FAK000999999', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_101', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', 'PHENOMENE', '[{"gear":"TBN","mesh":100,"dimensions":"250;180"},{"gear":"OTT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW04","segmentName":"Chaluts pélagiques"},{"segment":"SWW06","segmentName":"Sennes"}]', '{"riskFactor":2.1,"catchOnboard":[{"weight":25,"nbFish":null,"species":"COD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, software, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (101, 'FAKE_OPERATION_101', NULL, 'FAK000999999', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_101', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'JT/VISIOCaptures V1.4.7', 'ERS', 'PHENOMENE', '[{"gear":"TBN","mesh":100,"dimensions":"250;180"},{"gear":"OTT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW04","segmentName":"Chaluts pélagiques"},{"segment":"SWW06","segmentName":"Sennes"}]', '{"riskFactor":2.1,"catchOnboard":[{"weight":25,"nbFish":null,"species":"COD","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":false,"pnoTypes":[{"pnoTypeName":"Préavis type A","minimumNotificationPeriod":4,"hasDesignatedPorts":false},{"pnoTypeName":"Préavis type B","minimumNotificationPeriod":8,"hasDesignatedPorts":true}],"port":"FRSML","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 101; UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedLandingDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '3.5 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 101; UPDATE logbook_reports SET value = JSONB_SET(value, '{tripStartDate}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' - INTERVAL '10 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 101; -INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, transmission_format, value) VALUES (1101, NULL, 'FAKE_OPERATION_101', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_101_RET', 'RET', 'ERS', '{"returnStatus":"000"}'); +INSERT INTO logbook_reports (id, report_id, referenced_report_id, integration_datetime_utc, operation_datetime_utc, operation_number, operation_type, software, transmission_format, value) VALUES (1101, NULL, 'FAKE_OPERATION_101', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes', 'FAKE_OPERATION_101_RET', 'RET', 'JT/VISIOCaptures V1.4.7', 'ERS', '{"returnStatus":"000"}'); INSERT INTO logbook_reports (id, report_id, referenced_report_id, cfr, enriched, flag_state, integration_datetime_utc, log_type, operation_datetime_utc, operation_number, operation_type, report_datetime_utc, transmission_format, vessel_name, trip_gears, trip_segments, value) VALUES (102, 'FAKE_OPERATION_102', NULL, 'ABC000042310', true, 'FRA', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'PNO', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'FAKE_OPERATION_102', 'DAT', NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes', 'ERS', 'COURANT MAIN PROFESSEUR', '[{"gear":"PT","mesh":100,"dimensions":"250;180"},{"gear":"OT","mesh":120.5,"dimensions":"250;280"}]', '[{"segment":"SWW10","segmentName":"Palangres ciblant les espèces démersales"},{"segment":"SWW11","segmentName":"Hameçons"}]', '{"riskFactor":2.8,"catchOnboard":[{"weight":25,"nbFish":null,"species":"SOL","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"},{"weight":25,"nbFish":null,"species":"HKE","faoZone":"27.8.a","effortZone":"C","economicZone":"FRA","statisticalRectangle":"23E6"}],"isBeingSent":false,"isInVerificationScope":false,"isSent":true,"isVerified":true,"pnoTypes":[{"pnoTypeName":"Préavis type C","minimumNotificationPeriod":4,"hasDesignatedPorts":false}],"port":"FRBES","predictedArrivalDatetimeUtc":null,"predictedLandingDatetimeUtc":null,"purpose":"LAN","tripStartDate":null}'); UPDATE logbook_reports SET value = JSONB_SET(value, '{predictedArrivalDatetimeUtc}', TO_JSONB(TO_CHAR(NOW() AT TIME ZONE 'UTC' + INTERVAL '4 hours', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')), true) WHERE id = 102; diff --git a/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc b/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc index baf2865312..004350c2e0 100644 --- a/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc +++ b/backend/src/main/resources/db/testdata/json/V666.5.1__Insert_more_pno_logbook_reports.jsonc @@ -57,6 +57,7 @@ "operation_number": "FAKE_OPERATION_101", "operation_type": "DAT", "report_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '15 minutes'", + "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "vessel_name": "PHENOMENE", "trip_gears:jsonb": [ @@ -111,6 +112,7 @@ "operation_datetime_utc:sql": "NOW() AT TIME ZONE 'UTC' - INTERVAL '14 minutes'", "operation_number": "FAKE_OPERATION_101_RET", "operation_type": "RET", + "software": "JT/VISIOCaptures V1.4.7", "transmission_format": "ERS", "value:jsonb": { "returnStatus": "000" From 49fe62aed6e1bf758f7d68b7452a44b216288a1a Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Thu, 15 Aug 2024 19:46:31 +0200 Subject: [PATCH 22/26] Fix prior reset in prior notifiaction update e2e test --- .../e2e/side_window/prior_notification_card/card.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts index fad87567fd..ba4ae5e59f 100644 --- a/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts +++ b/frontend/cypress/e2e/side_window/prior_notification_card/card.spec.ts @@ -133,7 +133,9 @@ context('Side Window > Prior Notification Card > Card', () => { }) it('Should update a logbook prior notification', () => { - cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${dayjs().toISOString()}`, { + // Reset + const operationDate = dayjs().subtract(6, 'hours').toISOString() + cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${operationDate}`, { body: { authorTrigram: null, note: null @@ -166,7 +168,6 @@ context('Side Window > Prior Notification Card > Card', () => { cy.get('[name="authorTrigram"]').should('have.value', 'ABC') // Reset - const operationDate = dayjs().subtract(6, 'hours').toISOString() cy.request('PUT', `/bff/v1/prior_notifications/logbook/FAKE_OPERATION_114?operationDate=${operationDate}`, { body: { authorTrigram: null, From 098efbc9cf15912b5e095a43d50df41c8ad5bd37 Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 16 Aug 2024 10:32:47 +0200 Subject: [PATCH 23/26] Simplify jpa repository --- .../GetPriorNotifications.kt | 5 +- .../JpaLogbookReportRepository.kt | 201 ++++++------------ .../interfaces/DBLogbookReportRepository.kt | 5 + 3 files changed, 66 insertions(+), 145 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt index a4c57cc918..83a0d0d346 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/use_cases/prior_notification/GetPriorNotifications.kt @@ -58,11 +58,8 @@ class GetPriorNotifications( val incompletePriorNotifications = automaticPriorNotifications + manualPriorNotifications - val undeletedPriorNotifications = incompletePriorNotifications - .filter { !it.logbookMessageAndValue.logbookMessage.isDeleted } - val (priorNotifications, enrichedPriorNotificationsTimeTaken) = measureTimedValue { - undeletedPriorNotifications + incompletePriorNotifications .map { priorNotification -> priorNotification.enrich(allRiskFactors, allPorts, priorNotification.isManuallyCreated) priorNotification.logbookMessageAndValue.logbookMessage diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index ec77baea34..9d3da54fe6 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -35,7 +35,7 @@ class JpaLogbookReportRepository( ) : LogbookReportRepository { override fun findAllAcknowledgedPriorNotifications(filter: PriorNotificationsFilter): List { // Acknowledged "DAT", "COR" and "DEL" operations - val logbookReportModelsWithCorAndDel = + val logbookReportsWithDatCorAndDel = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations( flagStates = filter.flagStates ?: emptyList(), hasOneOrMoreReportings = filter.hasOneOrMoreReportings, @@ -52,17 +52,17 @@ class JpaLogbookReportRepository( willArriveBefore = filter.willArriveBefore, ) - val datAndOrphanCorLogbooReportModels = logbookReportModelsWithCorAndDel + val logbookMessageReferencingOtherMessages = logbookReportsWithDatCorAndDel.filter { it.referencedReportId != null } + return logbookReportsWithDatCorAndDel .filter { - it.operationType == LogbookOperationType.DAT || ( - it.operationType == LogbookOperationType.COR && - logbookReportModelsWithCorAndDel.none { model -> model.reportId == it.referencedReportId } - ) + logbookMessageReferencingOtherMessages.none { + referencingMessage -> + referencingMessage.referencedReportId == it.reportId + } + }.filter { it.operationType != LogbookOperationType.DEL } + .map { + PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) } - - return datAndOrphanCorLogbooReportModels.map { - resolveAsPriorNotification(it, logbookReportModelsWithCorAndDel, objectMapper) - } } @Cacheable(value = ["pno_to_verify"]) @@ -80,26 +80,21 @@ class JpaLogbookReportRepository( } /** - * Return null if the logbook report is deleted by an aknowledged "DEL" operation. + * Return null if the logbook report: + * - is not found + * - is deleted by an acknowledged "DEL" operation + * - is corrected by an acknowledged "COR" operation */ override fun findAcknowledgedPriorNotificationByReportId( reportId: String, operationDate: ZonedDateTime, ): PriorNotification? { - // Acknowledged "DAT" and "COR" operations - val logbookReportModelsWithCor = dbLogbookReportRepository - .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.toString()) - val datOrOrphanCorLogbookReportModel = logbookReportModelsWithCor.firstOrNull { - it.operationType == LogbookOperationType.DAT || ( - it.operationType == LogbookOperationType.COR && - logbookReportModelsWithCor.none { model -> model.reportId == it.referencedReportId } - ) - } - if (datOrOrphanCorLogbookReportModel == null) { - return null - } + val logbookReport = dbLogbookReportRepository + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.toString()).firstOrNull() - return resolveAsPriorNotification(datOrOrphanCorLogbookReportModel, logbookReportModelsWithCor, objectMapper) + return logbookReport?.let { + PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) + } } override fun findLastTripBeforeDateTime( @@ -347,19 +342,20 @@ class JpaLogbookReportRepository( isSent: Boolean, isVerified: Boolean, ) { - val logbookReportModel = - findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate.withZoneSameInstant(UTC)) - ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) + val logbookReport = dbLogbookReportRepository + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.withZoneSameInstant(UTC).toString()).firstOrNull() + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) - pnoMessage.isBeingSent = isBeingSent - pnoMessage.isSent = isSent - pnoMessage.isVerified = isVerified + val pnoValue = objectMapper.readValue(logbookReport.message, PNO::class.java) - val nextPnoMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedModel = logbookReportModel.copy(message = nextPnoMessage) + val nextPnoValue = pnoValue.apply { + this.isBeingSent = isBeingSent + this.isSent = isSent + this.isVerified = isVerified + } + val updatedLogbookReport = logbookReport.copy(message = objectMapper.writeValueAsString(nextPnoValue)) - dbLogbookReportRepository.save(updatedModel) + dbLogbookReportRepository.save(updatedLogbookReport) } @Transactional @@ -370,130 +366,53 @@ class JpaLogbookReportRepository( authorTrigram: String?, note: String?, ) { - val logbookReportModel = - findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate.withZoneSameInstant(UTC)) - ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) + val logbookReport = dbLogbookReportRepository + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.withZoneSameInstant(UTC).toString()).firstOrNull() + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) + val pnoValue = objectMapper.readValue(logbookReport.message, PNO::class.java) if ( - Utils.areStringsEqual(authorTrigram, pnoMessage.authorTrigram) && - Utils.areStringsEqual(note, pnoMessage.note) + Utils.areStringsEqual(authorTrigram, pnoValue.authorTrigram) && + Utils.areStringsEqual(note, pnoValue.note) ) { return } - pnoMessage.authorTrigram = authorTrigram - pnoMessage.note = note - /** - * The PNO states are re-initialized: - * - the PDF will be re-generated (done in the use case by deleting the old one) - * - the PNO will require another verification before sending - */ - pnoMessage.isBeingSent = false - pnoMessage.isSent = false - pnoMessage.isVerified = false - - val nextPnoMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedModel = logbookReportModel.copy(message = nextPnoMessage) - - dbLogbookReportRepository.save(updatedModel) + val nextPnoValue = pnoValue.apply { + this.authorTrigram = authorTrigram + this.note = note + /** + * The PNO states are re-initialized: + * - the PDF will be re-generated (done in the use case by deleting the old one) + * - the PNO will require another verification before sending + */ + this.isBeingSent = false + this.isSent = false + this.isVerified = false + } + val updatedLogbookReport = logbookReport.copy(message = objectMapper.writeValueAsString(nextPnoValue)) + + dbLogbookReportRepository.save(updatedLogbookReport) } @Transactional @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { - val logbookReportModel = - findAcknowledgedPnoLogbookReportModelByReportId(reportId, operationDate.withZoneSameInstant(UTC)) - ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) + val logbookReport = dbLogbookReportRepository + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.withZoneSameInstant(UTC).toString()).firstOrNull() + ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) - val pnoMessage = objectMapper.readValue(logbookReportModel.message, PNO::class.java) - pnoMessage.isInvalidated = true + val pnoValue = objectMapper.readValue(logbookReport.message, PNO::class.java) - val nextPnoMessage = objectMapper.writeValueAsString(pnoMessage) - val updatedModel = logbookReportModel.copy(message = nextPnoMessage) - - dbLogbookReportRepository.save(updatedModel) - } - - /** - * Return null if the logbook report is deleted by an aknowledged "DEL" operation. - */ - private fun findAcknowledgedPnoLogbookReportModelByReportId( - reportId: String, - operationDate: ZonedDateTime, - ): LogbookReportEntity? { - // Acknowledged "DAT" and "COR" operations - val logbookReportModelsWithCor = dbLogbookReportRepository - .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.toString()) - logbookReportModelsWithCor.forEach { println("${it.reportId}") } - val datOrOrphanCorLogbookReportModel = logbookReportModelsWithCor.firstOrNull { - it.operationType == LogbookOperationType.DAT || ( - it.operationType == LogbookOperationType.COR && - logbookReportModelsWithCor.none { model -> model.reportId == it.referencedReportId } - ) - } - if (datOrOrphanCorLogbookReportModel == null) { - return null + val nextPnoValue = pnoValue.apply { + this.isInvalidated = true } - return resolveAsLogbookReportModel(datOrOrphanCorLogbookReportModel, logbookReportModelsWithCor) + val updatedLogbookReport = logbookReport.copy(message = objectMapper.writeValueAsString(nextPnoValue)) + + dbLogbookReportRepository.save(updatedLogbookReport) } private fun getAllMessagesExceptionMessage(internalReferenceNumber: String) = "No messages found for the vessel. (internalReferenceNumber: \"$internalReferenceNumber\")" - - companion object { - private fun resolveAsLogbookReportModel( - parent: LogbookReportEntity, - list: List, - ): LogbookReportEntity { - val child = list.find { it.referencedReportId == parent.reportId } - - return when { - child?.operationType == LogbookOperationType.COR -> { - child - } - - child?.reportId == null -> { - parent - } - - else -> resolveAsLogbookReportModel(child, list) - } - } - - private fun resolveAsPriorNotification( - parent: LogbookReportEntity, - list: List, - objectMapper: ObjectMapper, - ): PriorNotification { - val child = list.find { it.referencedReportId == parent.reportId } - - return when { - child?.operationType == LogbookOperationType.DEL -> { - val deletedParent = PriorNotification.fromLogbookMessage(parent.toLogbookMessage(objectMapper)) - deletedParent.markAsAcknowledged() - deletedParent.markAsDeleted() - - deletedParent - } - - child?.reportId == null && child?.operationType == LogbookOperationType.COR -> { - val corChild = PriorNotification.fromLogbookMessage(child.toLogbookMessage(objectMapper)) - corChild.markAsAcknowledged() - - corChild - } - - child?.reportId == null -> { - val datOrCorParent = PriorNotification.fromLogbookMessage(parent.toLogbookMessage(objectMapper)) - datOrCorParent.markAsAcknowledged() - - datOrCorParent - } - - else -> resolveAsPriorNotification(child, list, objectMapper) - } - } - } } diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt index 992cdc4063..8e92415885 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/interfaces/DBLogbookReportRepository.kt @@ -181,6 +181,11 @@ interface DBLogbookReportRepository : willArriveBefore: String, ): List + /** + * This query either returns: + * - 1 element if the report id is found, not corrected and not deleted + * - 0 element + */ @Query( """ WITH From 97455b1a23d3f5437269bc6bbe974dec423b0ca6 Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 16 Aug 2024 11:04:58 +0200 Subject: [PATCH 24/26] Add acknowledgment --- .../prior_notification/PriorNotification.kt | 11 ++-------- .../JpaLogbookReportRepository.kt | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt index febd369fd4..c1ee89b178 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/domain/entities/prior_notification/PriorNotification.kt @@ -146,13 +146,6 @@ data class PriorNotification( ) } - fun markAsDeleted() { - logbookMessageAndValue = LogbookMessageAndValue( - logbookMessageAndValue.logbookMessage.copy(isDeleted = true), - PNO::class.java, - ) - } - companion object { private val logger = LoggerFactory.getLogger(PriorNotification::class.java) @@ -187,11 +180,11 @@ data class PriorNotification( * Used within the prior notification form to display the next state of the prior notification in real-time. */ fun getNextState( - isInverificationScope: Boolean, + isInVerificationScope: Boolean, isPartOfControlUnitSubscriptions: Boolean, ): PriorNotificationState { return when { - isInverificationScope -> PriorNotificationState.PENDING_VERIFICATION + isInVerificationScope -> PriorNotificationState.PENDING_VERIFICATION isPartOfControlUnitSubscriptions -> PriorNotificationState.AUTO_SEND_REQUESTED else -> PriorNotificationState.OUT_OF_VERIFICATION_SCOPE } diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 9d3da54fe6..7ecf43c180 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -61,7 +61,11 @@ class JpaLogbookReportRepository( } }.filter { it.operationType != LogbookOperationType.DEL } .map { - PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) + val pno = PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) + // All messages returned from the SQL query are acknowledged + pno.markAsAcknowledged() + + return@map pno } } @@ -343,7 +347,10 @@ class JpaLogbookReportRepository( isVerified: Boolean, ) { val logbookReport = dbLogbookReportRepository - .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.withZoneSameInstant(UTC).toString()).firstOrNull() + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId( + reportId, + operationDate.withZoneSameInstant(UTC).toString(), + ).firstOrNull() ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val pnoValue = objectMapper.readValue(logbookReport.message, PNO::class.java) @@ -367,7 +374,10 @@ class JpaLogbookReportRepository( note: String?, ) { val logbookReport = dbLogbookReportRepository - .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.withZoneSameInstant(UTC).toString()).firstOrNull() + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId( + reportId, + operationDate.withZoneSameInstant(UTC).toString(), + ).firstOrNull() ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val pnoValue = objectMapper.readValue(logbookReport.message, PNO::class.java) @@ -399,7 +409,10 @@ class JpaLogbookReportRepository( @CacheEvict(value = ["pno_to_verify"], allEntries = true) override fun invalidate(reportId: String, operationDate: ZonedDateTime) { val logbookReport = dbLogbookReportRepository - .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.withZoneSameInstant(UTC).toString()).firstOrNull() + .findAcknowledgedNonDeletedPnoDatAndCorsByReportId( + reportId, + operationDate.withZoneSameInstant(UTC).toString(), + ).firstOrNull() ?: throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND) val pnoValue = objectMapper.readValue(logbookReport.message, PNO::class.java) From d5442483146edc2748bf42afdd99f251d47ac168 Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 16 Aug 2024 11:12:54 +0200 Subject: [PATCH 25/26] Improve perf --- .../JpaLogbookReportRepository.kt | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index 7ecf43c180..fa94bc8c20 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -52,16 +52,18 @@ class JpaLogbookReportRepository( willArriveBefore = filter.willArriveBefore, ) - val logbookMessageReferencingOtherMessages = logbookReportsWithDatCorAndDel.filter { it.referencedReportId != null } + val referencedReportIds = logbookReportsWithDatCorAndDel + .filter { it.referencedReportId != null } + .map { it.referencedReportId } + .toSet() + return logbookReportsWithDatCorAndDel - .filter { - logbookMessageReferencingOtherMessages.none { - referencingMessage -> - referencingMessage.referencedReportId == it.reportId - } - }.filter { it.operationType != LogbookOperationType.DEL } - .map { - val pno = PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) + .filter { report -> + // Exclude reports that are referenced by other reports or have a DEL operation type + report.operationType != LogbookOperationType.DEL && report.reportId !in referencedReportIds + } + .map { report -> + val pno = PriorNotification.fromLogbookMessage(report.toLogbookMessage(objectMapper)) // All messages returned from the SQL query are acknowledged pno.markAsAcknowledged() From 7e52afd2e809477c97006dcb13c51e5fdbccef1e Mon Sep 17 00:00:00 2001 From: Loup Theron Date: Fri, 16 Aug 2024 11:20:36 +0200 Subject: [PATCH 26/26] Add acknowledgment of single pno --- .../database/repositories/JpaLogbookReportRepository.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt index fa94bc8c20..1dcd32c13b 100644 --- a/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt +++ b/backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/infrastructure/database/repositories/JpaLogbookReportRepository.kt @@ -99,7 +99,10 @@ class JpaLogbookReportRepository( .findAcknowledgedNonDeletedPnoDatAndCorsByReportId(reportId, operationDate.toString()).firstOrNull() return logbookReport?.let { - PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) + val pno = PriorNotification.fromLogbookMessage(it.toLogbookMessage(objectMapper)) + pno.markAsAcknowledged() + + return@let pno } }