Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Préavis – Ajouter des pastilles indiquant le nombre de préavis à vérifier #3447

Merged
merged 9 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ interface LogbookReportRepository {
isVerified: Boolean,
)

fun findAllPriorNotificationsToVerify(): List<PriorNotification>

fun updatePriorNotificationNote(reportId: String, operationDate: ZonedDateTime, note: String?)

// For test purpose
fun deleteAll()
fun updatePriorNotificationNote(reportId: String, operationDate: ZonedDateTime, note: String?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ interface ManualPriorNotificationRepository {
fun save(newOrNextPriorNotification: PriorNotification): PriorNotification

fun updateState(reportId: String, isBeingSent: Boolean, isVerified: Boolean)

fun findAllToVerify(): List<PriorNotification>
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ class CreateOrUpdateManualPriorNotification(
tripGearCodes: List<String>,
vesselId: Int,
): PriorNotification {
val existingManualPriorNotification = reportId?.let { manualPriorNotificationRepository.findByReportId(it) }
val existingPnoMessage = existingManualPriorNotification?.logbookMessageTyped?.typedMessage

// /!\ Backend computed vessel risk factor is only used as a real time Frontend indicator.
// The Backend should NEVER update `risk_factors` DB table, only the pipeline is allowed to update it.
val computedValues = computeManualPriorNotification.execute(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.facade.SeafrontGroup
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationStats
import fr.gouv.cnsp.monitorfish.domain.repositories.*

@UseCase
class GetNumberToVerify(
private val logbookReportRepository: LogbookReportRepository,
private val manualPriorNotificationRepository: ManualPriorNotificationRepository,
private val portRepository: PortRepository,
private val riskFactorRepository: RiskFactorRepository,
private val vesselRepository: VesselRepository,
) {
fun execute(): PriorNotificationStats {
val allPorts = portRepository.findAll()
val allRiskFactors = riskFactorRepository.findAll()
val allVessels = vesselRepository.findAll()

val automaticPriorNotifications = logbookReportRepository.findAllPriorNotificationsToVerify()
val manualPriorNotifications = manualPriorNotificationRepository.findAllToVerify()
val incompletePriorNotifications = automaticPriorNotifications + manualPriorNotifications

val undeletedPriorNotifications = incompletePriorNotifications
.filter { !it.logbookMessageTyped.logbookMessage.isDeleted }

val priorNotifications = undeletedPriorNotifications
.map { priorNotification ->
priorNotification.enrich(allPorts, allRiskFactors, allVessels, priorNotification.isManuallyCreated)

priorNotification
}

return PriorNotificationStats(
perSeafrontGroupCount = SeafrontGroup.entries.associateWith { seafrontGroupEntry ->
priorNotifications.count { priorNotification ->
seafrontGroupEntry.hasSeafront(priorNotification.seafront)
}
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class PriorNotificationController(
private val createOrUpdateManualPriorNotification: CreateOrUpdateManualPriorNotification,
private val getPriorNotification: GetPriorNotification,
private val getPriorNotifications: GetPriorNotifications,
private val getNumberToVerify: GetNumberToVerify,
private val getPriorNotificationTypes: GetPriorNotificationTypes,
private val updatePriorNotificationNote: UpdatePriorNotificationNote,
private val verifyAndSendPriorNotification: VerifyAndSendPriorNotification,
Expand Down Expand Up @@ -125,6 +126,14 @@ class PriorNotificationController(
)
}

@GetMapping("/to_verify")
@Operation(summary = "Get number of prior notifications to verify")
fun getNumberToVerify(): PriorNotificationsExtraDataOutput {
val priorNotificationStats = getNumberToVerify.execute()

return PriorNotificationsExtraDataOutput.fromPriorNotificationStats(priorNotificationStats)
}

@PostMapping("/manual/compute")
@Operation(summary = "Calculate manual prior notification fleet segments, prior notification types and risk factor")
fun getManualComputation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class CaffeineConfiguration {
val nextLogbook = "next_logbook"
val previousLogbook = "previous_logbook"
val pnoTypes = "pno_types"
val pnoToVerify = "pno_to_verify"
val manualPnoToVerify = "manual_pno_to_verify"

// Missions
val missionControlUnits = "mission_control_units"
Expand Down Expand Up @@ -108,6 +110,8 @@ class CaffeineConfiguration {
val nextLogbookCache = buildMinutesCache(nextLogbook, ticker, 10)
val previousLogbookCache = buildMinutesCache(previousLogbook, ticker, 10)

val pnoToVerifyCache = buildMinutesCache(pnoToVerify, ticker, 5)
val manualPnoToVerifyCache = buildMinutesCache(manualPnoToVerify, ticker, 5)
val pnoTypesCache = buildMinutesCache(pnoTypes, ticker, 123)

// Missions
Expand Down Expand Up @@ -176,6 +180,8 @@ class CaffeineConfiguration {
missionControlUnitsCache,
nextLogbookCache,
pnoTypesCache,
pnoToVerifyCache,
manualPnoToVerifyCache,
portCache,
portsCache,
previousLogbookCache,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ 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
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
import org.springframework.data.domain.PageRequest
Expand Down Expand Up @@ -63,6 +65,42 @@ class JpaLogbookReportRepository(
}
}

@Cacheable(value = ["pno_to_verify"])
override fun findAllPriorNotificationsToVerify(): List<PriorNotification> {
val allLogbookReportModels = dbLogbookReportRepository.findAllEnrichedPnoReferencesAndRelatedOperations(
flagStates = emptyList(),
hasOneOrMoreReportings = null,
isLessThanTwelveMetersVessel = null,
lastControlledAfter = null,
lastControlledBefore = null,
portLocodes = emptyList(),
priorNotificationTypesAsSqlArrayString = null,
searchQuery = null,
specyCodesAsSqlArrayString = null,
tripGearCodesAsSqlArrayString = null,
tripSegmentCodesAsSqlArrayString = null,
willArriveAfter = CustomZonedDateTime(ZonedDateTime.now()).toString(),
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,
)

null
}
}.filter {
it.logbookMessageTyped.typedMessage.isInVerificationScope == true &&
it.logbookMessageTyped.typedMessage.isVerified == false
}
}

override fun findPriorNotificationByReportId(reportId: String, operationDate: ZonedDateTime): PriorNotification? {
val allLogbookReportModels = dbLogbookReportRepository.findEnrichedPnoReferenceAndRelatedOperationsByReportId(
reportId,
Expand Down Expand Up @@ -318,6 +356,7 @@ class JpaLogbookReportRepository(
}

@Transactional
@CacheEvict(value = ["pno_to_verify"], allEntries = true)
override fun updatePriorNotificationState(
reportId: String,
operationDate: ZonedDateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ import fr.gouv.cnsp.monitorfish.domain.repositories.ManualPriorNotificationRepos
import fr.gouv.cnsp.monitorfish.infrastructure.database.entities.ManualPriorNotificationEntity
import fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.interfaces.DBManualPriorNotificationRepository
import fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.utils.toSqlArrayString
import fr.gouv.cnsp.monitorfish.utils.CustomZonedDateTime
import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Repository
import org.springframework.transaction.annotation.Transactional
import java.time.ZonedDateTime
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
Expand Down Expand Up @@ -43,6 +47,30 @@ class JpaManualPriorNotificationRepository(
).map { it.toPriorNotification() }
}

@Cacheable(value = ["manual_pno_to_verify"])
override fun findAllToVerify(): List<PriorNotification> {
return dbManualPriorNotificationRepository
.findAll(
flagStates = emptyList(),
hasOneOrMoreReportings = null,
lastControlledAfter = null,
lastControlledBefore = null,
portLocodes = emptyList(),
priorNotificationTypesAsSqlArrayString = null,
searchQuery = null,
specyCodesAsSqlArrayString = null,
tripGearCodesAsSqlArrayString = null,
tripSegmentCodesAsSqlArrayString = null,
willArriveAfter = CustomZonedDateTime(ZonedDateTime.now()).toString(),
willArriveBefore = CustomZonedDateTime(ZonedDateTime.now().plusHours(24)).toString(),
).filter {
it.value.isInVerificationScope == true && it.value.isVerified == false
}
.map {
it.toPriorNotification()
}
}

override fun findByReportId(reportId: String): PriorNotification? {
return dbManualPriorNotificationRepository.findByReportId(reportId)?.toPriorNotification()
}
Expand All @@ -63,6 +91,7 @@ class JpaManualPriorNotificationRepository(
}

@Transactional
@CacheEvict(value = ["manual_pno_to_verify"], allEntries = true)
override fun updateState(reportId: String, isBeingSent: Boolean, isVerified: Boolean) {
val manualPriorNotificationEntity =
dbManualPriorNotificationRepository.findByReportId(reportId) ?: throw BackendUsageException(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import com.nhaarman.mockitokotlin2.given
import fr.gouv.cnsp.monitorfish.domain.entities.facade.SeafrontGroup
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessage
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessageTyped
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookOperationType
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookTransmissionFormat
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.prior_notification.PriorNotification
import fr.gouv.cnsp.monitorfish.domain.repositories.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension
import java.time.ZonedDateTime

@ExtendWith(SpringExtension::class)
class GetNumberToVerifyUTests {
@MockBean
private lateinit var logbookReportRepository: LogbookReportRepository

@MockBean
private lateinit var manualPriorNotificationRepository: ManualPriorNotificationRepository

@MockBean
private lateinit var portRepository: PortRepository

@MockBean
private lateinit var riskFactorRepository: RiskFactorRepository

@MockBean
private lateinit var vesselRepository: VesselRepository

@Test
fun `execute Should return a map of PNO for each facade to verify`() {
// Given
given(portRepository.findAll()).willReturn(
listOf(
Port("AEFJR", "Al Jazeera Port", facade = "NAMO"),
Port("AEFAT", "Al Jazeera Port", facade = "Guyane"),
Port("AEJAZ", "Arzanah Island", facade = "SA"),
),
)
given(logbookReportRepository.findAllPriorNotificationsToVerify()).willReturn(
listOf(
PriorNotification(
reportId = "FAKE_REPORT_ID_1",
authorTrigram = null,
createdAt = null,
didNotFishAfterZeroNotice = false,
isManuallyCreated = false,
logbookMessageTyped = LogbookMessageTyped(
clazz = PNO::class.java,
logbookMessage = LogbookMessage(
id = 1,
reportId = "FAKE_REPORT_ID_1",
referencedReportId = null,
integrationDateTime = ZonedDateTime.now(),
isCorrectedByNewerMessage = false,
isDeleted = false,
isEnriched = false,
message = PNO().apply { port = "AEFJR" },
operationDateTime = ZonedDateTime.now(),
operationNumber = "1",
operationType = LogbookOperationType.DAT,
reportDateTime = ZonedDateTime.now(),
transmissionFormat = LogbookTransmissionFormat.ERS,
),
),
port = null,
reportingCount = null,
seafront = null,
sentAt = null,
state = null,
updatedAt = null,
vessel = null,
lastControlDateTime = null,
),

PriorNotification(
reportId = "FAKE_REPORT_ID_2",
authorTrigram = null,
createdAt = null,
didNotFishAfterZeroNotice = false,
isManuallyCreated = false,
logbookMessageTyped = LogbookMessageTyped(
clazz = PNO::class.java,
logbookMessage = LogbookMessage(
id = 1,
reportId = "FAKE_REPORT_ID_2_COR",
referencedReportId = "FAKE_NONEXISTENT_REPORT_ID_2",
integrationDateTime = ZonedDateTime.now(),
isCorrectedByNewerMessage = false,
isDeleted = false,
isEnriched = false,
message = PNO().apply { port = "AEFAT" },
operationDateTime = ZonedDateTime.now(),
operationNumber = "1",
operationType = LogbookOperationType.COR,
reportDateTime = ZonedDateTime.now(),
transmissionFormat = LogbookTransmissionFormat.ERS,
),
),
port = null,
reportingCount = null,
seafront = null,
sentAt = null,
state = null,
updatedAt = null,
vessel = null,
lastControlDateTime = null,
),
),
)

// When
val result = GetNumberToVerify(
logbookReportRepository,
manualPriorNotificationRepository,
portRepository,
riskFactorRepository,
vesselRepository,
).execute()

// Then
assertThat(result.perSeafrontGroupCount.values).hasSize(8)
assertThat(result.perSeafrontGroupCount[SeafrontGroup.ALL]).isEqualTo(2)
assertThat(result.perSeafrontGroupCount[SeafrontGroup.NAMO]).isEqualTo(1)
assertThat(result.perSeafrontGroupCount[SeafrontGroup.OUTREMEROA]).isEqualTo(1)
assertThat(result.perSeafrontGroupCount[SeafrontGroup.NONE]).isEqualTo(0)
}
}
Loading
Loading