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 - Amélioration de la logique d'enregistrement, de téléchargement et de diffusion #3380

Merged
merged 3 commits into from
Jul 8, 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 @@ -4,4 +4,5 @@ import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PdfDocument

interface PriorNotificationPdfDocumentRepository {
fun findByReportId(reportId: String): PdfDocument
fun deleteByReportId(reportId: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import fr.gouv.cnsp.monitorfish.domain.entities.logbook.messages.PNO
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.ManualPriorNotificationComputedValues
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotification
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationType
import fr.gouv.cnsp.monitorfish.domain.repositories.GearRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.ManualPriorNotificationRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.PortRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.VesselRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.time.ZonedDateTime

@UseCase
Expand All @@ -20,8 +19,11 @@ class CreateOrUpdateManualPriorNotification(
private val portRepository: PortRepository,
private val vesselRepository: VesselRepository,
private val computeManualPriorNotification: ComputeManualPriorNotification,
private val priorNotificationPdfDocumentRepository: PriorNotificationPdfDocumentRepository,
private val getPriorNotification: GetPriorNotification,
) {
private val logger: Logger = LoggerFactory.getLogger(CreateOrUpdateManualPriorNotification::class.java)

fun execute(
hasPortEntranceAuthorization: Boolean,
hasPortLandingAuthorization: Boolean,
Expand Down Expand Up @@ -126,6 +128,14 @@ class CreateOrUpdateManualPriorNotification(
updatedAt = null,
)

if (reportId !== null) {
try {
priorNotificationPdfDocumentRepository.deleteByReportId(reportId)
} catch (e: Exception) {
logger.warn("Could not delete existing PDF document", e)
}
}

val newOrCurrentReportId = manualPriorNotificationRepository.save(newOrNextPriorNotification)
val createdOrUpdatedPriorNotification = getPriorNotification.execute(newOrCurrentReportId, true)

Expand Down Expand Up @@ -164,10 +174,10 @@ 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.isBeingSent = isInVerificationScope
this.isBeingSent = false
this.isInVerificationScope = isInVerificationScope
this.isSent = false
this.isVerified = existingPnoValue?.isVerified ?: false
this.isVerified = false
this.latitude = null
this.longitude = null
this.note = note
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@ package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification
import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotification
import fr.gouv.cnsp.monitorfish.domain.repositories.LogbookReportRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationPdfDocumentRepository
import org.slf4j.Logger
import org.slf4j.LoggerFactory

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

fun execute(
note: String?,
reportId: String,
): PriorNotification {
try {
priorNotificationPdfDocumentRepository.deleteByReportId(reportId)
} catch (e: Exception) {
logger.warn("Could not delete existing PDF document", e)
}

logbookReportRepository.updatePriorNotificationNote(
reportId = reportId,
note = note,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ data class PriorNotificationPdfDocumentEntity(
@Id
@Column(name = "report_id")
val reportId: String,

@Column(name = "source", columnDefinition = "prior_notification_source")
@Enumerated(EnumType.STRING)
@JdbcType(PostgreSQLEnumJdbcType::class)
val source: PriorNotificationSource,

@Column(name = "generation_datetime_utc")
val generationDatetimeUtc: ZonedDateTime,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,15 @@ class JpaLogbookReportRepository(
val pnoMessage = objectMapper.readValue(logbookReportEntity.message, PNO::class.java)
pnoMessage.note = note

/**
* The PNO states are re-initialized,
* - the PDF will be generated
* - the PNO will require another verification before sending
*/
pnoMessage.isBeingSent = false
pnoMessage.isVerified = false
pnoMessage.isSent = false

val nextMessage = objectMapper.writeValueAsString(pnoMessage)

val updatedEntity = logbookReportEntity.copy(message = nextMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import fr.gouv.cnsp.monitorfish.domain.exceptions.BackendUsageException
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationPdfDocumentRepository
import fr.gouv.cnsp.monitorfish.infrastructure.database.repositories.interfaces.DBPriorNotificationPdfDocumentRepository
import org.springframework.dao.EmptyResultDataAccessException
import org.springframework.data.jpa.repository.Modifying
import org.springframework.stereotype.Repository

@Repository
Expand All @@ -19,4 +20,13 @@ class JpaPriorNotificationPdfDocumentRepository(
throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND)
}
}

@Modifying(clearAutomatically = true)
override fun deleteByReportId(reportId: String) {
return try {
dbPriorNotificationPdfDocumentRepository.deleteById(reportId)
} catch (e: EmptyResultDataAccessException) {
throw BackendUsageException(BackendUsageErrorCode.NOT_FOUND)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.given
import fr.gouv.cnsp.monitorfish.domain.entities.logbook.LogbookMessagePurpose
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.ManualPriorNotificationComputedValues
import fr.gouv.cnsp.monitorfish.domain.repositories.GearRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.ManualPriorNotificationRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.PortRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.VesselRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.*
import fr.gouv.cnsp.monitorfish.fakers.PriorNotificationFaker
import fr.gouv.cnsp.monitorfish.fakers.VesselFaker
import org.assertj.core.api.Assertions.assertThat
Expand Down Expand Up @@ -37,6 +34,9 @@ class CreateOrUpdateManualPriorNotificationUTests {
@MockBean
private lateinit var getPriorNotification: GetPriorNotification

@MockBean
private lateinit var priorNotificationPdfDocumentRepository: PriorNotificationPdfDocumentRepository

@Test
fun `execute Should update a manual prior notification`() {
val fakePriorNotification = PriorNotificationFaker.fakePriorNotification()
Expand All @@ -62,6 +62,7 @@ class CreateOrUpdateManualPriorNotificationUTests {
portRepository,
vesselRepository,
computeManualPriorNotification,
priorNotificationPdfDocumentRepository,
getPriorNotification,
).execute(
hasPortEntranceAuthorization = true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import com.nhaarman.mockitokotlin2.given
import fr.gouv.cnsp.monitorfish.domain.repositories.LogbookReportRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationPdfDocumentRepository
import fr.gouv.cnsp.monitorfish.fakers.PriorNotificationFaker
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

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

@MockBean
private lateinit var getPriorNotification: GetPriorNotification

@MockBean
private lateinit var priorNotificationPdfDocumentRepository: PriorNotificationPdfDocumentRepository

@Test
fun `execute Should update a prior notification note`() {
val fakePriorNotification = PriorNotificationFaker.fakePriorNotification()

// Given
given(getPriorNotification.execute(fakePriorNotification.reportId!!, false)).willReturn(fakePriorNotification)

// When
val result = UpdatePriorNotificationNote(
logbookReportRepository,
priorNotificationPdfDocumentRepository,
getPriorNotification,
).execute(
note = null,
reportId = fakePriorNotification.reportId!!,
)

// Then
assertThat(result.reportId).isEqualTo(fakePriorNotification.reportId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1174,8 +1174,14 @@ class JpaLogbookReportRepositoryITests : AbstractDBTests() {
// 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)
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)
assertThat((updatedCorReport.message as PNO).isSent).isEqualTo(false)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package fr.gouv.cnsp.monitorfish.infrastructure.database.repositories

import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationSource
import fr.gouv.cnsp.monitorfish.domain.exceptions.BackendUsageErrorCode
import fr.gouv.cnsp.monitorfish.domain.exceptions.BackendUsageException
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.catchThrowable
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.transaction.annotation.Transactional
Expand All @@ -24,4 +27,24 @@ class JpaPriorNotificationPdfDocumentRepositoryITests : AbstractDBTests() {
assertThat(pdfDocument.generationDatetimeUtc).isEqualTo(ZonedDateTime.parse("2024-07-03T14:45:00Z"))
assertThat(pdfDocument.pdfDocument).isNotNull()
}

@Test
@Transactional
fun `deleteByReportId Should delete a pdf document`() {
// Given
val existingPdfDocument = jpaPriorNotificationPdfDocumentRepository.findByReportId("FAKE_OPERATION_102")
assertThat(existingPdfDocument.reportId).isEqualTo("FAKE_OPERATION_102")

// When
jpaPriorNotificationPdfDocumentRepository.deleteByReportId("FAKE_OPERATION_102")

// Then
val throwable = catchThrowable {
jpaPriorNotificationPdfDocumentRepository.findByReportId("FAKE_OPERATION_102")
}

// Then
assertThat(throwable).isNotNull()
assertThat((throwable as BackendUsageException).code).isEqualTo(BackendUsageErrorCode.NOT_FOUND)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ context('Side Window > Prior Notification Card > Card', () => {
})
})

it('Should update a note', () => {
it('Should update a note and delete the current PDF', () => {
// Given
openSideWindowPriorNotification(`CALAMARO`)
cy.get('*[name="note"]').should('have.value', '')
Expand All @@ -195,7 +195,11 @@ context('Side Window > Prior Notification Card > Card', () => {
cy.get('*[name="note"]').should('have.value', "Un point d'attention.")
cy.wait('@updatePriorNotificationNote')

// Then, the note is saved
// Then, the PDF is deleted
cy.clickButton('Télécharger les documents')
cy.get('li[aria-disabled="true"]').contains('Préavis de débarquement (Document non généré)')

// The note is saved
openSideWindowPriorNotification(`CALAMARO`)
cy.get('*[name="note"]').should('have.value', "Un point d'attention.")
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@ context('Side Window > Prior Notification Form > Form', () => {
reportId: createdPriorNotification.reportId
})

cy.clickButton('Télécharger les documents')
cy.get('li[aria-disabled="true"]').contains('Préavis de débarquement (Document non généré)')

// -----------------------------------------------------------------------
// List

Expand Down Expand Up @@ -429,6 +432,24 @@ context('Side Window > Prior Notification Form > Form', () => {
cy.countRequestsByAlias('@computePriorNotification', 1500).should('be.equal', 6)
})

it('Should permit the resending of an updated manual PNO', () => {
// Given
cy.intercept(
'POST',
'/bff/v1/prior_notifications/00000000-0000-4000-0000-000000000002/verify_and_send?isManuallyCreated=true'
).as('verifyAndSendPriorNotification')
editSideWindowPriorNotification('DOS FIN', '00000000-0000-4000-0000-000000000002')
cy.get('button').contains('Diffusé')
cy.fill('Saisi par', 'BOB')

// When
cy.clickButton('Enregistrer')

// Then
cy.clickButton('Diffuser')
cy.wait('@verifyAndSendPriorNotification')
})

it('Should verify and send a manual prior notification', () => {
// -------------------------------------------------------------------------
// Add
Expand Down Expand Up @@ -484,7 +505,7 @@ context('Side Window > Prior Notification Form > Form', () => {
cy.get('.Element-Tag').contains('Hors diffusion').should('exist')

// -----------------------------------------------------------------------
// Veryify and send
// Verify and send

cy.intercept(
'POST',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type RTKBaseQueryArgs =
// Mutation
| {
body?: AnyObject
method: 'DELETE' | 'POST' | 'PUT'
method: 'GET' | 'DELETE' | 'POST' | 'PUT'
/** URL Path (and not full URL). */
url: string
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export function PriorNotificationCard() {
state => state.displayedError.sideWindowPriorNotificationCardError
)
const [isLoading, setIsLoading] = useState(false)
const isPendingSend = priorNotificationDetail?.state === PriorNotification.State.PENDING_SEND
const isSent = [PriorNotification.State.SENT, PriorNotification.State.VERIFIED_AND_SENT].includes(
priorNotificationDetail?.state as any
)
Expand Down Expand Up @@ -180,7 +179,7 @@ export function PriorNotificationCard() {
<FormikTextarea
label="Points d'attention identifiés par le CNSP"
name="note"
readOnly={isPendingSend || isSent || !isSuperUser}
readOnly={!isSuperUser}
/>
</FieldGroup>
</>
Expand All @@ -193,14 +192,13 @@ export function PriorNotificationCard() {
</Button>

<DownloadButton
isPdfDocumentAvailable={isSent}
pnoLogbookMessage={priorNotificationDetail.logbookMessage}
reportId={priorNotificationDetail.id}
/>

<Button
accent={Accent.PRIMARY}
disabled={isPendingSend || isSent}
disabled={isSent}
Icon={isSent ? Icon.Check : Icon.Send}
onClick={verifyAndSend}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,15 @@ export function Card({ isValidatingOnChange, onClose, onSubmit, onVerifyAndSend,

{!!editedPriorNotificationDetail && (
<DownloadButton
isDisabled={dirty && (!isSent || !isPendingSend)}
isPdfDocumentAvailable={isSent}
isDisabled={dirty}
pnoLogbookMessage={editedPriorNotificationDetail.logbookMessage}
reportId={editedPriorNotificationDetail.id}
/>
)}

<Button
accent={Accent.PRIMARY}
disabled={!dirty || isPendingSend || isSent || (isValidatingOnChange && !isValid)}
disabled={!dirty || (isValidatingOnChange && !isValid)}
onClick={handleSubmit}
>
{isNewPriorNotification ? 'Créer le préavis' : 'Enregistrer'}
Expand Down
Loading
Loading