Skip to content

Commit

Permalink
Préavis – Garder une trace des différentes modifications (#3771)
Browse files Browse the repository at this point in the history
## Linked issues

- Resolve #3346

----

- [x] Tests E2E (Cypress)
  • Loading branch information
ivangabriele authored Oct 17, 2024
2 parents 2f3fe9a + 00fb33d commit ad89c3a
Show file tree
Hide file tree
Showing 43 changed files with 2,155 additions and 2,735 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ class PNO() : LogbookMessageValue {
var hasPortEntranceAuthorization: Boolean? = null
var hasPortLandingAuthorization: Boolean? = null

@Deprecated(
"""
Kept because some historical messages used a manually entered trigram to identify the author of the message.
It's now automated via `createdBy` and `updatedBy` fields.
""",
)
var authorTrigram: String? = null
var catchOnboard: List<LogbookFishingCatch> = emptyList()
var catchToLand: List<LogbookFishingCatch> = emptyList()
var createdBy: String? = null
var economicZone: String? = null
var effortZone: String? = null

Expand Down Expand Up @@ -69,4 +76,9 @@ class PNO() : LogbookMessageValue {
@JsonDeserialize(using = ZonedDateTimeDeserializer::class)
@JsonSerialize(using = ZonedDateTimeSerializer::class)
var tripStartDate: ZonedDateTime? = null

@JsonDeserialize(using = ZonedDateTimeDeserializer::class)
@JsonSerialize(using = ZonedDateTimeSerializer::class)
var updatedAt: ZonedDateTime? = null
var updatedBy: String? = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ data class PriorNotification(
isManuallyCreated = false,
logbookMessageAndValue = logbookMessageAndValue,
sentAt = logbookMessageAndValue.logbookMessage.reportDateTime,
updatedAt = logbookMessage.operationDateTime,
updatedAt = logbookMessageAndValue.value.updatedAt ?: logbookMessage.operationDateTime,
// These props need to be calculated in the use case
port = null,
reportingCount = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ interface LogbookReportRepository {

fun findAllPriorNotificationsToVerify(): List<PriorNotification>

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

fun invalidate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class CreateOrUpdateManualPriorNotification(

fun execute(
reportId: String?,
authorTrigram: String,
author: String?,
didNotFishAfterZeroNotice: Boolean,
expectedArrivalDate: ZonedDateTime,
expectedLandingDate: ZonedDateTime,
Expand All @@ -44,11 +44,17 @@ class CreateOrUpdateManualPriorNotification(
hasPortLandingAuthorization: Boolean,
note: String?,
portLocode: String,
sentAt: ZonedDateTime,
purpose: LogbookMessagePurpose,
sentAt: ZonedDateTime,
tripGearCodes: List<String>,
vesselId: Int,
): PriorNotification {
val existingMessageValue: PNO? =
reportId?.let {
val manualPriorNotfication = manualPriorNotificationRepository.findByReportId(reportId)
manualPriorNotfication?.logbookMessageAndValue?.logbookMessage?.message as PNO
}

// /!\ 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 =
Expand All @@ -72,9 +78,9 @@ class CreateOrUpdateManualPriorNotification(
val tripSegments = computedValues.tripSegments.map { it.toLogbookTripSegment() }
val vessel = vesselRepository.findVesselById(vesselId)
val priorNotificationTypes = computedValues.types.map { it.toPriorNotificationType() }
val message =
getMessage(
authorTrigram = authorTrigram,
val messageValue =
getMessageValue(
existingMessageValue = existingMessageValue,
expectedArrivalDate = expectedArrivalDate,
expectedLandingDate = expectedLandingDate,
// At the moment, manual prior notifications only have a single global FAO area field in Frontend,
Expand All @@ -86,6 +92,7 @@ class CreateOrUpdateManualPriorNotification(
pnoTypes = priorNotificationTypes,
portLocode = portLocode,
purpose = purpose,
author = author,
computedVesselFlagCountryCode = vessel?.flagState,
computedVesselRiskFactor = computedValues.vesselRiskFactor,
isPartOfControlUnitSubscriptions = isPartOfControlUnitSubscriptions,
Expand Down Expand Up @@ -116,7 +123,7 @@ class CreateOrUpdateManualPriorNotification(
isDeleted = false,
isEnriched = true,
isSentByFailoverSoftware = false,
message = message,
message = messageValue,
messageType = LogbookMessageTypeMapping.PNO.name,
operationType = LogbookOperationType.DAT,
tripGears = tripGears,
Expand Down Expand Up @@ -163,8 +170,8 @@ class CreateOrUpdateManualPriorNotification(
return createdOrUpdatedPriorNotification
}

private fun getMessage(
authorTrigram: String,
private fun getMessageValue(
existingMessageValue: PNO?,
purpose: LogbookMessagePurpose,
expectedArrivalDate: ZonedDateTime,
expectedLandingDate: ZonedDateTime,
Expand All @@ -174,24 +181,29 @@ class CreateOrUpdateManualPriorNotification(
note: String?,
pnoTypes: List<PriorNotificationType>,
portLocode: String,
author: String?,
computedVesselFlagCountryCode: CountryCode?,
computedVesselRiskFactor: Double?,
isPartOfControlUnitSubscriptions: Boolean,
): PNO {
val allPorts = portRepository.findAll()

val authorTrigram = existingMessageValue?.authorTrigram
val createdBy = existingMessageValue?.createdBy ?: author
val isInVerificationScope =
ManualPriorNotificationComputedValues
.isInVerificationScope(computedVesselFlagCountryCode, computedVesselRiskFactor)
// If the prior notification is not in verification scope,
// we pass `isBeingSent` as `true` in order to ask the workflow to send it.
val isBeingSent = !isInVerificationScope && isPartOfControlUnitSubscriptions
val portName = allPorts.find { it.locode == portLocode }?.name
val updatedBy = if (existingMessageValue != null) author else null

return PNO().apply {
this.authorTrigram = authorTrigram
this.catchOnboard = fishingCatches
this.catchToLand = fishingCatches
this.createdBy = createdBy
this.economicZone = null
this.effortZone = null
// At the moment, manual prior notifications only have a single global FAO area field in Frontend,
Expand All @@ -218,6 +230,7 @@ class CreateOrUpdateManualPriorNotification(
this.statisticalRectangle = null
this.tripStartDate = null
this.riskFactor = computedVesselRiskFactor
this.updatedBy = updatedBy
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class UpdateLogbookPriorNotification(
fun execute(
reportId: String,
operationDate: ZonedDateTime,
authorTrigram: String?,
note: String?,
updatedBy: 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
Expand All @@ -30,11 +30,11 @@ class UpdateLogbookPriorNotification(
logger.warn("Could not delete existing PDF document", e)
}

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

return getPriorNotification.execute(reportId, operationDate, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import fr.gouv.cnsp.monitorfish.infrastructure.api.input.LogbookPriorNotificatio
import fr.gouv.cnsp.monitorfish.infrastructure.api.input.ManualPriorNotificationComputeDataInput
import fr.gouv.cnsp.monitorfish.infrastructure.api.input.ManualPriorNotificationFormDataInput
import fr.gouv.cnsp.monitorfish.infrastructure.api.outputs.*
import fr.gouv.cnsp.monitorfish.infrastructure.api.security.UserAuthorizationCheckFilter
import fr.gouv.cnsp.monitorfish.infrastructure.exceptions.BackendRequestErrorCode
import fr.gouv.cnsp.monitorfish.infrastructure.exceptions.BackendRequestException
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletResponse
import jakarta.websocket.server.PathParam
import org.springframework.data.domain.Sort
import org.springframework.http.HttpHeaders
Expand Down Expand Up @@ -165,6 +167,7 @@ class PriorNotificationController(
@PutMapping("/logbook/{reportId}")
@Operation(summary = "Update a logbook prior notification by its `reportId`")
fun updateLogbook(
response: HttpServletResponse,
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
reportId: String,
Expand All @@ -178,8 +181,8 @@ class PriorNotificationController(
updateLogbookPriorNotification.execute(
reportId = reportId,
operationDate = operationDate,
authorTrigram = logbookPriorNotificationFormDataInput.authorTrigram,
note = logbookPriorNotificationFormDataInput.note,
updatedBy = response.getHeader(UserAuthorizationCheckFilter.EMAIL_HEADER),
)

return LogbookPriorNotificationFormDataOutput.fromPriorNotification(updatedPriorNotification)
Expand Down Expand Up @@ -211,19 +214,20 @@ class PriorNotificationController(
@PostMapping("/manual")
@Operation(summary = "Create a new manual prior notification")
fun createManual(
response: HttpServletResponse,
@RequestBody
manualPriorNotificationFormDataInput: ManualPriorNotificationFormDataInput,
): ManualPriorNotificationFormDataOutput {
val createdPriorNotification =
createOrUpdateManualPriorNotification.execute(
hasPortEntranceAuthorization = manualPriorNotificationFormDataInput.hasPortEntranceAuthorization,
hasPortLandingAuthorization = manualPriorNotificationFormDataInput.hasPortLandingAuthorization,
authorTrigram = manualPriorNotificationFormDataInput.authorTrigram,
author = response.getHeader(UserAuthorizationCheckFilter.EMAIL_HEADER),
didNotFishAfterZeroNotice = manualPriorNotificationFormDataInput.didNotFishAfterZeroNotice,
expectedArrivalDate = manualPriorNotificationFormDataInput.expectedArrivalDate,
expectedLandingDate = manualPriorNotificationFormDataInput.expectedLandingDate,
globalFaoArea = manualPriorNotificationFormDataInput.globalFaoArea,
fishingCatches = manualPriorNotificationFormDataInput.fishingCatches.map { it.toLogbookFishingCatch() },
globalFaoArea = manualPriorNotificationFormDataInput.globalFaoArea,
hasPortEntranceAuthorization = manualPriorNotificationFormDataInput.hasPortEntranceAuthorization,
hasPortLandingAuthorization = manualPriorNotificationFormDataInput.hasPortLandingAuthorization,
note = manualPriorNotificationFormDataInput.note,
portLocode = manualPriorNotificationFormDataInput.portLocode,
reportId = null,
Expand All @@ -239,6 +243,7 @@ class PriorNotificationController(
@PutMapping("/manual/{reportId}")
@Operation(summary = "Update a manual prior notification by its `reportId`")
fun updateManual(
response: HttpServletResponse,
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
reportId: String,
Expand All @@ -247,14 +252,14 @@ class PriorNotificationController(
): ManualPriorNotificationFormDataOutput {
val updatedPriorNotification =
createOrUpdateManualPriorNotification.execute(
hasPortEntranceAuthorization = manualPriorNotificationFormDataInput.hasPortEntranceAuthorization,
hasPortLandingAuthorization = manualPriorNotificationFormDataInput.hasPortLandingAuthorization,
authorTrigram = manualPriorNotificationFormDataInput.authorTrigram,
author = response.getHeader(UserAuthorizationCheckFilter.EMAIL_HEADER),
didNotFishAfterZeroNotice = manualPriorNotificationFormDataInput.didNotFishAfterZeroNotice,
expectedArrivalDate = manualPriorNotificationFormDataInput.expectedArrivalDate,
expectedLandingDate = manualPriorNotificationFormDataInput.expectedLandingDate,
globalFaoArea = manualPriorNotificationFormDataInput.globalFaoArea,
fishingCatches = manualPriorNotificationFormDataInput.fishingCatches.map { it.toLogbookFishingCatch() },
globalFaoArea = manualPriorNotificationFormDataInput.globalFaoArea,
hasPortEntranceAuthorization = manualPriorNotificationFormDataInput.hasPortEntranceAuthorization,
hasPortLandingAuthorization = manualPriorNotificationFormDataInput.hasPortLandingAuthorization,
note = manualPriorNotificationFormDataInput.note,
portLocode = manualPriorNotificationFormDataInput.portLocode,
reportId = reportId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.gouv.cnsp.monitorfish.infrastructure.api.input

data class LogbookPriorNotificationFormDataInput(
val authorTrigram: String?,
val note: String?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import java.time.ZonedDateTime
data class ManualPriorNotificationFormDataInput(
val hasPortEntranceAuthorization: Boolean,
val hasPortLandingAuthorization: Boolean,
val authorTrigram: String,
val didNotFishAfterZeroNotice: Boolean,
val expectedArrivalDate: ZonedDateTime,
val expectedLandingDate: ZonedDateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package fr.gouv.cnsp.monitorfish.infrastructure.api.outputs
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotification

data class LogbookPriorNotificationFormDataOutput(
val authorTrigram: String?,
val note: String?,
) {
companion object {
fun fromPriorNotification(priorNotification: PriorNotification): LogbookPriorNotificationFormDataOutput {
return LogbookPriorNotificationFormDataOutput(
authorTrigram = priorNotification.logbookMessageAndValue.value.authorTrigram,
note = priorNotification.logbookMessageAndValue.value.note,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import fr.gouv.cnsp.monitorfish.utils.CustomZonedDateTime
import java.time.ZoneOffset
import java.time.ZonedDateTime

@Suppress("NullableBooleanElvis")
data class ManualPriorNotificationFormDataOutput(
val reportId: String,
val hasPortEntranceAuthorization: Boolean,
val hasPortLandingAuthorization: Boolean,
val authorTrigram: String,
val didNotFishAfterZeroNotice: Boolean,
val expectedArrivalDate: String,
val expectedLandingDate: String,
val fishingCatches: List<ManualPriorNotificationFishingCatchDataOutput>,
val globalFaoArea: String?,
val hasPortEntranceAuthorization: Boolean,
val hasPortLandingAuthorization: Boolean,
val note: String?,
val portLocode: String,
val sentAt: ZonedDateTime,
Expand All @@ -29,10 +29,6 @@ data class ManualPriorNotificationFormDataOutput(
val logbookMessage = priorNotification.logbookMessageAndValue.logbookMessage
val pnoValue = priorNotification.logbookMessageAndValue.value

val authorTrigram =
requireNotNull(pnoValue.authorTrigram) {
"`pnoValue.authorTrigram` is null."
}
val expectedArrivalDate =
CustomZonedDateTime.fromZonedDateTime(
requireNotNull(pnoValue.predictedArrivalDatetimeUtc) {
Expand Down Expand Up @@ -85,7 +81,6 @@ data class ManualPriorNotificationFormDataOutput(

return ManualPriorNotificationFormDataOutput(
reportId = reportId,
authorTrigram = authorTrigram,
didNotFishAfterZeroNotice = priorNotification.didNotFishAfterZeroNotice,
expectedArrivalDate = expectedArrivalDate,
expectedLandingDate = expectedLandingDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class PriorNotificationDataOutput(
val asLogbookForm: LogbookPriorNotificationFormDataOutput?,
val asManualDraft: ManualPriorNotificationDraftDataOutput?,
val asManualForm: ManualPriorNotificationFormDataOutput?,
val createdAt: ZonedDateTime,
/** Unique identifier concatenating all the DAT, COR, RET & DEL operations `id` used for data consolidation. */
val fingerprint: String,
val isLessThanTwelveMetersVessel: Boolean,
Expand All @@ -19,6 +20,7 @@ class PriorNotificationDataOutput(
val operationDate: ZonedDateTime,
val state: PriorNotificationState?,
val riskFactor: Double?,
val updatedAt: ZonedDateTime,
val vesselId: Int,
val vesselIdentity: VesselIdentityDataOutput,
) {
Expand Down Expand Up @@ -52,9 +54,18 @@ class PriorNotificationDataOutput(
requireNotNull(priorNotification.vessel) {
"`priorNotification.vessel` is null."
}

val createdAt =
requireNotNull(priorNotification.createdAt) {
"`priorNotification.createdAt` is null."
}
val isLessThanTwelveMetersVessel = vessel.isLessThanTwelveMetersVessel()
val isVesselUnderCharter = vessel.underCharter
val logbookMessage = priorNotification.logbookMessageAndValue.logbookMessage
val updatedAt =
requireNotNull(priorNotification.updatedAt) {
"`priorNotification.updatedAt` is null."
}
val vesselIdentity = VesselIdentityDataOutput.fromVessel(vessel)
val vesselId = vessel.id

Expand All @@ -65,6 +76,7 @@ class PriorNotificationDataOutput(
asLogbookForm = asLogbookForm,
asManualDraft = asManualDraft,
asManualForm = asManualForm,
createdAt = createdAt,
fingerprint = priorNotification.fingerprint,
isLessThanTwelveMetersVessel = isLessThanTwelveMetersVessel,
isManuallyCreated = priorNotification.isManuallyCreated,
Expand All @@ -73,6 +85,7 @@ class PriorNotificationDataOutput(
operationDate = logbookMessage.operationDateTime,
state = priorNotification.state,
riskFactor = priorNotification.logbookMessageAndValue.value.riskFactor,
updatedAt = updatedAt,
vesselId = vesselId,
vesselIdentity = vesselIdentity,
)
Expand Down
Loading

0 comments on commit ad89c3a

Please sign in to comment.