Skip to content

Commit

Permalink
[Préavis] Ajoute le champ trigramme dans le formulaire des préavis au…
Browse files Browse the repository at this point in the history
…to (#3483)

## Linked issues

- Resolve #3412
- Resolve #3459
- Resolve #3471
- Resolve #3458
- Resolve #3430
- Resolve #3436
- Resolve #3317
- Resolve #3401

----

- [ ] Tests E2E (Cypress)
  • Loading branch information
ivangabriele committed Aug 7, 2024
2 parents 6cfc76e + ea97aad commit 4dbfb06
Show file tree
Hide file tree
Showing 87 changed files with 1,261 additions and 899 deletions.
12 changes: 6 additions & 6 deletions adrs/0006-prior-notification-states-specifications.md

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions backend/src/main/kotlin/fr/gouv/cnsp/monitorfish/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fr.gouv.cnsp.monitorfish

class Utils {
companion object {
/**
* Compares two strings by trimming them and checking if they are equivalent:
*
* If both strings are null or empty, they are considered equivalent.
*/
fun areStringsEqual(leftString: String?, rightString: String?): Boolean {
val normalizedLeftString = leftString?.trim().takeUnless { it.isNullOrEmpty() || it == " " }
val normalizedRightString = rightString?.trim().takeUnless { it.isNullOrEmpty() || it == " " }

return normalizedLeftString == normalizedRightString
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class PNO() : LogbookMessageValue {
var hasPortEntranceAuthorization: Boolean? = null
var hasPortLandingAuthorization: Boolean? = null

var authorTrigram: String? = null
var catchOnboard: List<LogbookFishingCatch> = emptyList()
var catchToLand: List<LogbookFishingCatch> = emptyList()
var economicZone: String? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package fr.gouv.cnsp.monitorfish.domain.entities.prior_notification

import com.neovisionaries.i18n.CountryCode
import fr.gouv.cnsp.monitorfish.domain.entities.fleet_segment.FleetSegment
import fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification.VESSEL_FLAG_COUNTRY_CODES_WITHOUT_SYSTEMATIC_VERIFICATION
import fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification.VESSEL_RISK_FACTOR_VERIFICATION_THRESHOLD

val VESSEL_FLAG_COUNTRY_CODES_WITHOUT_SYSTEMATIC_VERIFICATION: List<CountryCode> = listOf(CountryCode.FR)
const val VESSEL_RISK_FACTOR_VERIFICATION_THRESHOLD: Double = 2.3

/**
* Real-time computed values displayed within a prior notification form.
* Real-time computed values displayed within a manual prior notification form.
*/
data class ManualPriorNotificationComputedValues(
val isVesselUnderCharter: Boolean?,
/** Next initial state of the prior notification once it will be created or updated. */
/** Next initial state of the manual prior notification once it will be created or updated. */
val nextState: PriorNotificationState,
val tripSegments: List<FleetSegment>,
val types: List<PnoType>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import java.time.ZonedDateTime

data class PriorNotification(
val reportId: String?,
val authorTrigram: String?,
val createdAt: ZonedDateTime?,
val didNotFishAfterZeroNotice: Boolean,
val isManuallyCreated: Boolean,
Expand All @@ -35,7 +34,7 @@ data class PriorNotification(
var lastControlDateTime: ZonedDateTime?,
) {
/** Each prior notification and each of its updates have a unique fingerprint. */
val fingerprint: String = listOf(reportId, updatedAt).joinToString(separator = ".")
val fingerprint: String = listOf(reportId, updatedAt, state).joinToString(separator = ".")
private val logger = LoggerFactory.getLogger(PriorNotification::class.java)

val state: PriorNotificationState?
Expand All @@ -53,7 +52,7 @@ data class PriorNotification(
return when {
isInVerificationScope == null || isVerified == null || isSent == null || isBeingSent == null -> null
!isInVerificationScope && !isVerified && !isSent && !isBeingSent -> PriorNotificationState.OUT_OF_VERIFICATION_SCOPE
!isInVerificationScope && !isVerified && !isSent && isBeingSent -> PriorNotificationState.AUTO_SEND_IN_PROGRESS
!isInVerificationScope && !isVerified && !isSent && isBeingSent -> PriorNotificationState.PENDING_AUTO_SEND
!isInVerificationScope && !isVerified && isSent && !isBeingSent -> PriorNotificationState.AUTO_SEND_DONE
!isInVerificationScope && isVerified && !isSent && !isBeingSent -> PriorNotificationState.FAILED_SEND
!isInVerificationScope && isVerified && !isSent && isBeingSent -> PriorNotificationState.PENDING_SEND
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ enum class PriorNotificationState {
/** "Envoi auto. demandé". */
AUTO_SEND_REQUESTED,

/** "En cours d'envoi auto.". */
AUTO_SEND_IN_PROGRESS,

/** "Envoi auto. fait". */
AUTO_SEND_DONE,

Expand All @@ -16,10 +13,10 @@ enum class PriorNotificationState {
/** "Hors vérification". */
OUT_OF_VERIFICATION_SCOPE,

/** "En cours de d'envoi auto". */
/** "Envoi auto. en cours". */
PENDING_AUTO_SEND,

/** "En cours de diffusion". */
/** "Diffusion en cours". */
PENDING_SEND,

/** "À vérifier (CNSP)". */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,21 @@ interface LogbookReportRepository {
fun updatePriorNotificationState(
reportId: String,
operationDate: ZonedDateTime,

isBeingSent: Boolean,
isSent: Boolean,
isVerified: Boolean,
)

fun findAllPriorNotificationsToVerify(): List<PriorNotification>

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

authorTrigram: String?,
note: String?,
)

fun invalidate(reportId: String, operationDate: ZonedDateTime)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import com.neovisionaries.i18n.CountryCode
import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookFishingCatch
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.ManualPriorNotificationComputedValues
Expand All @@ -11,9 +10,6 @@ import fr.gouv.cnsp.monitorfish.domain.repositories.PnoVesselSubscriptionReposit
import fr.gouv.cnsp.monitorfish.domain.repositories.VesselRepository
import fr.gouv.cnsp.monitorfish.domain.use_cases.fleet_segment.ComputeFleetSegments

val VESSEL_FLAG_COUNTRY_CODES_WITHOUT_SYSTEMATIC_VERIFICATION: List<CountryCode> = listOf(CountryCode.FR)
const val VESSEL_RISK_FACTOR_VERIFICATION_THRESHOLD: Double = 2.3

@UseCase
class ComputeManualPriorNotification(
private val pnoPortSubscriptionRepository: PnoPortSubscriptionRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,18 @@ class CreateOrUpdateManualPriorNotification(
private val logger: Logger = LoggerFactory.getLogger(CreateOrUpdateManualPriorNotification::class.java)

fun execute(
hasPortEntranceAuthorization: Boolean,
hasPortLandingAuthorization: Boolean,
reportId: String?,

authorTrigram: String,
didNotFishAfterZeroNotice: Boolean,
expectedArrivalDate: ZonedDateTime,
expectedLandingDate: ZonedDateTime,
faoArea: String,
fishingCatches: List<LogbookFishingCatch>,
hasPortEntranceAuthorization: Boolean,
hasPortLandingAuthorization: Boolean,
note: String?,
portLocode: String,
reportId: String?,
sentAt: ZonedDateTime,
purpose: LogbookMessagePurpose,
tripGearCodes: List<String>,
Expand All @@ -65,13 +66,14 @@ class CreateOrUpdateManualPriorNotification(
val vessel = vesselRepository.findVesselById(vesselId)
val priorNotificationTypes = computedValues.types.map { it.toPriorNotificationType() }
val message = getMessage(
hasPortEntranceAuthorization = hasPortEntranceAuthorization,
hasPortLandingAuthorization = hasPortLandingAuthorization,
authorTrigram = authorTrigram,
expectedArrivalDate = expectedArrivalDate,
expectedLandingDate = expectedLandingDate,
// At the moment, manual prior notifications only have a single global FAO area field in Frontend,
// so we transform that single FAO area into an FAO area per fishing catch.
fishingCatches = fishingCatchesWithFaoArea,
hasPortEntranceAuthorization = hasPortEntranceAuthorization,
hasPortLandingAuthorization = hasPortLandingAuthorization,
note = note,
pnoTypes = priorNotificationTypes,
portLocode = portLocode,
Expand Down Expand Up @@ -115,7 +117,6 @@ class CreateOrUpdateManualPriorNotification(

val newOrNextPriorNotification = PriorNotification(
reportId = reportId,
authorTrigram = authorTrigram,
didNotFishAfterZeroNotice = didNotFishAfterZeroNotice,
isManuallyCreated = true,
logbookMessageAndValue = logbookMessageAndValue,
Expand All @@ -131,6 +132,8 @@ class CreateOrUpdateManualPriorNotification(
updatedAt = null,
)

// Any update must trigger a new PDF generation, so we delete the existing PDF document
// which is re-generated by the Pipeline each time a PDF is deleted
if (reportId !== null) {
try {
priorNotificationPdfDocumentRepository.deleteByReportId(reportId)
Expand All @@ -151,12 +154,13 @@ class CreateOrUpdateManualPriorNotification(
}

private fun getMessage(
hasPortEntranceAuthorization: Boolean,
hasPortLandingAuthorization: Boolean,
authorTrigram: String,
purpose: LogbookMessagePurpose,
expectedArrivalDate: ZonedDateTime,
expectedLandingDate: ZonedDateTime,
fishingCatches: List<LogbookFishingCatch>,
hasPortEntranceAuthorization: Boolean,
hasPortLandingAuthorization: Boolean,
note: String?,
pnoTypes: List<PriorNotificationType>,
portLocode: String,
Expand All @@ -174,8 +178,7 @@ class CreateOrUpdateManualPriorNotification(
val portName = allPorts.find { it.locode == portLocode }?.name

return PNO().apply {
this.hasPortEntranceAuthorization = hasPortEntranceAuthorization
this.hasPortLandingAuthorization = hasPortLandingAuthorization
this.authorTrigram = authorTrigram
this.catchOnboard = fishingCatches
this.catchToLand = fishingCatches
this.economicZone = null
Expand All @@ -184,6 +187,8 @@ class CreateOrUpdateManualPriorNotification(
// so we transform that single FAO area into an FAO area per fishing catch.
// This means we don't need to set a global PNO message FAO area here.
this.faoZone = null
this.hasPortEntranceAuthorization = hasPortEntranceAuthorization
this.hasPortLandingAuthorization = hasPortLandingAuthorization
// If the prior notification is not in verification scope,
// we pass `isBeingSent` as `true` in order to ask the workflow to send it.
this.isBeingSent = isBeingSent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,31 @@ import org.slf4j.LoggerFactory
import java.time.ZonedDateTime

@UseCase
class UpdatePriorNotificationNote(
class UpdateLogbookPriorNotification(
private val logbookReportRepository: LogbookReportRepository,
private val priorNotificationPdfDocumentRepository: PriorNotificationPdfDocumentRepository,
private val getPriorNotification: GetPriorNotification,
) {
private val logger: Logger = LoggerFactory.getLogger(CreateOrUpdateManualPriorNotification::class.java)
private val logger: Logger = LoggerFactory.getLogger(UpdateLogbookPriorNotification::class.java)

fun execute(
reportId: String,
operationDate: ZonedDateTime,
authorTrigram: String?,
note: String?,
): PriorNotification {
// Any update must trigger a new PDF generation, so we delete the existing PDF document
// which is re-generated by the Pipeline each time a PDF is deleted
try {
priorNotificationPdfDocumentRepository.deleteByReportId(reportId)
} catch (e: Exception) {
logger.warn("Could not delete existing PDF document", e)
}

logbookReportRepository.updatePriorNotificationNote(
logbookReportRepository.updatePriorNotificationAuthorTrigramAndNote(
reportId = reportId,
operationDate = operationDate,
authorTrigram = authorTrigram,
note = note,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class VerifyAndSendPriorNotification(
reportId,
operationDate,
isBeingSent = true,
isSent = false,
isVerified = true,
)
}
Expand Down
Loading

0 comments on commit 4dbfb06

Please sign in to comment.