-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #92 from MTES-MCT/RPN-63
Rapport de patrouille
- Loading branch information
Showing
29 changed files
with
1,526 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...main/kotlin/fr/gouv/dgampa/rapportnav/domain/repositories/mission/IRpnExportRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package fr.gouv.dgampa.rapportnav.domain.repositories.mission | ||
|
||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.crew.MissionCrewEntity | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.export.MissionExportEntity | ||
import java.time.LocalDate | ||
import java.time.ZonedDateTime | ||
|
||
data class ExportParams( | ||
val service: String?, | ||
val id: String, | ||
val startDateTime: ZonedDateTime?, | ||
val endDateTime: ZonedDateTime?, | ||
val presenceMer: Map<String, Int>, | ||
val presenceQuai: Map<String, Int>, | ||
val indisponibilite: Map<String, Int>, | ||
val nbJoursMer: Int, | ||
val dureeMission: Int, | ||
val patrouilleEnv: Int, | ||
val patrouilleMigrant: Int, | ||
val distanceMilles: Float?, | ||
val goMarine: Float?, | ||
val essence: Float?, | ||
val crew: List<MissionCrewEntity>, | ||
val timeline: Map<LocalDate, List<String>>? | ||
) | ||
|
||
interface IRpnExportRepository { | ||
fun exportOdt(params: ExportParams): MissionExportEntity? | ||
} |
23 changes: 23 additions & 0 deletions
23
backend/src/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/GetMissionById.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package fr.gouv.dgampa.rapportnav.domain.use_cases.mission | ||
|
||
import fr.gouv.dgampa.rapportnav.config.UseCase | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.MissionEntity | ||
import org.slf4j.LoggerFactory | ||
|
||
@UseCase | ||
class GetMissionById( | ||
private val getEnvMissionById: GetEnvMissionById, | ||
private val getFishActionsByMissionId: GetFishActionsByMissionId, | ||
private val getNavMissionById: GetNavMissionById, | ||
) { | ||
private val logger = LoggerFactory.getLogger(GetMissionById::class.java) | ||
|
||
fun execute(missionId: Int): MissionEntity? { | ||
val envMission = getEnvMissionById.execute(missionId = missionId) ?: return null | ||
val fishMissionActions = getFishActionsByMissionId.execute(missionId = missionId) | ||
val navMission = getNavMissionById.execute(missionId = missionId) | ||
|
||
return MissionEntity(envMission, navMission, fishMissionActions) | ||
} | ||
|
||
} |
21 changes: 21 additions & 0 deletions
21
...ain/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/action/GroupActionByDate.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package fr.gouv.dgampa.rapportnav.domain.use_cases.mission.action | ||
|
||
import fr.gouv.dgampa.rapportnav.config.UseCase | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.MissionActionEntity | ||
import java.time.LocalDate | ||
|
||
@UseCase | ||
class GroupActionByDate { | ||
fun execute(actions: List<MissionActionEntity>?): Map<LocalDate, List<MissionActionEntity>>? { | ||
return actions?.groupBy { action -> | ||
when (action) { | ||
is MissionActionEntity.EnvAction -> action.envAction?.controlAction?.action?.actionStartDateTimeUtc?.toLocalDate() | ||
is MissionActionEntity.FishAction -> action.fishAction.controlAction?.action?.actionDatetimeUtc?.toLocalDate() | ||
is MissionActionEntity.NavAction -> action.navAction.startDateTimeUtc.toLocalDate() | ||
else -> null // Handle other types of actions, if any | ||
} | ||
}?.mapNotNull { (date, actions) -> | ||
date?.let { it to actions } | ||
}?.toMap() | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
...rc/main/kotlin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/ExportMission.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package fr.gouv.dgampa.rapportnav.domain.use_cases.mission.export | ||
|
||
import fr.gouv.dgampa.rapportnav.config.UseCase | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.MissionEntity | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.crew.MissionCrewEntity | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.export.MissionExportEntity | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.generalInfo.MissionGeneralInfoEntity | ||
import fr.gouv.dgampa.rapportnav.domain.repositories.mission.ExportParams | ||
import fr.gouv.dgampa.rapportnav.domain.repositories.mission.IRpnExportRepository | ||
import fr.gouv.dgampa.rapportnav.domain.repositories.mission.action.INavActionStatusRepository | ||
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.GetMissionById | ||
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.crew.GetAgentsCrewByMissionId | ||
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.generalInfo.GetMissionGeneralInfoByMissionId | ||
import org.slf4j.LoggerFactory | ||
|
||
@UseCase | ||
class ExportMission( | ||
private val exportRepository: IRpnExportRepository, | ||
private val getMissionGeneralInfoByMissionId: GetMissionGeneralInfoByMissionId, | ||
private val agentsCrewByMissionId: GetAgentsCrewByMissionId, | ||
private val getMissionById: GetMissionById, | ||
private val navActionStatus: INavActionStatusRepository, | ||
private val mapStatusDurations: MapStatusDurations, | ||
private val formatActionsForTimeline: FormatActionsForTimeline, | ||
) { | ||
|
||
private val logger = LoggerFactory.getLogger(ExportMission::class.java) | ||
|
||
fun exportOdt(missionId: Int): MissionExportEntity? { | ||
try { | ||
val mission: MissionEntity? = getMissionById.execute(missionId = missionId) | ||
if (mission == null) { | ||
logger.error("[exportOdt] Mission not found for missionId: $missionId") | ||
return null | ||
} | ||
|
||
val generalInfo: MissionGeneralInfoEntity? = getMissionGeneralInfoByMissionId.execute(missionId) | ||
val agentsCrew: List<MissionCrewEntity> = agentsCrewByMissionId.execute(missionId = missionId) | ||
val statuses = navActionStatus.findAllByMissionId(missionId = missionId).sortedBy { it.startDateTimeUtc } | ||
.map { it.toActionStatusEntity() } | ||
|
||
val durations = mapStatusDurations.execute(mission, statuses) | ||
val missionDuration = (durations["atSeaDurations"]?.get("total") ?: 0) + | ||
(durations["dockingDurations"]?.get("total") ?: 0) + | ||
(durations["unavailabilityDurations"]?.get("total") ?: 0) | ||
|
||
val timeline = formatActionsForTimeline.formatTimeline(mission.actions) | ||
|
||
val exportParams = ExportParams( | ||
service = mission.openBy, | ||
id = "pam" + mission.id, | ||
startDateTime = mission.startDateTimeUtc, | ||
endDateTime = mission.endDateTimeUtc, | ||
presenceMer = durations["atSeaDurations"].orEmpty(), | ||
presenceQuai = durations["dockingDurations"].orEmpty(), | ||
indisponibilite = durations["unavailabilityDurations"].orEmpty(), | ||
nbJoursMer = 0, | ||
dureeMission = missionDuration, | ||
patrouilleEnv = 0, | ||
patrouilleMigrant = 0, | ||
distanceMilles = generalInfo?.distanceInNauticalMiles, | ||
goMarine = generalInfo?.consumedGOInLiters, | ||
essence = generalInfo?.consumedFuelInLiters, | ||
crew = agentsCrew, | ||
timeline = timeline | ||
) | ||
|
||
return exportRepository.exportOdt(exportParams) | ||
} catch (e: Exception) { | ||
logger.error("[exportOdt] error occurred during exportOdt: ${e.message}") | ||
return null | ||
} | ||
} | ||
|
||
} |
144 changes: 144 additions & 0 deletions
144
...lin/fr/gouv/dgampa/rapportnav/domain/use_cases/mission/export/FormatActionsForTimeline.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package fr.gouv.dgampa.rapportnav.domain.use_cases.mission.export | ||
|
||
import fr.gouv.dgampa.rapportnav.config.UseCase | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.MissionActionEntity | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.env.envActions.EnvActionControlEntity | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.fish.fishActions.InfractionType | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.fish.fishActions.MissionAction | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.action.* | ||
import fr.gouv.dgampa.rapportnav.domain.entities.mission.nav.status.mapActionStatusTypeToHumanString | ||
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.action.GroupActionByDate | ||
import java.time.LocalDate | ||
import java.time.ZonedDateTime | ||
|
||
@UseCase | ||
class FormatActionsForTimeline( | ||
private val groupActionByDate: GroupActionByDate, | ||
) { | ||
|
||
fun formatTimeline(actions: List<MissionActionEntity>?): Map<LocalDate, List<String>>? { | ||
|
||
if (actions.isNullOrEmpty()) { | ||
return null | ||
} | ||
// Group actions by date | ||
val groupedActions = groupActionByDate.execute(actions = actions) | ||
|
||
// Map each group to list of formatted strings | ||
return groupedActions?.mapValues { (_, actionsOnDate) -> | ||
actionsOnDate.mapNotNull { action -> | ||
formatAction(action) | ||
} | ||
} | ||
} | ||
|
||
private fun formatAction(action: MissionActionEntity): String? { | ||
return when (action) { | ||
is MissionActionEntity.EnvAction -> formatEnvAction(action) | ||
is MissionActionEntity.FishAction -> formatFishAction(action) | ||
is MissionActionEntity.NavAction -> formatNavAction(action) | ||
} | ||
} | ||
|
||
private fun formatEnvAction(action: MissionActionEntity.EnvAction): String? { | ||
return action.envAction?.controlAction?.action?.let { envControlAction -> | ||
formatEnvControl(envControlAction) | ||
} | ||
} | ||
|
||
private fun formatFishAction(action: MissionActionEntity.FishAction): String? { | ||
return action.fishAction.controlAction?.action?.let { fishControlAction -> | ||
formatFishControl(fishControlAction) | ||
} | ||
} | ||
|
||
private fun formatNavAction(action: MissionActionEntity.NavAction): String? { | ||
val navAction = action.navAction | ||
return when (navAction.actionType) { | ||
ActionType.NOTE -> formatNavNote(navAction.freeNoteAction) | ||
ActionType.STATUS -> formatNavStatus(navAction.statusAction) | ||
ActionType.CONTROL -> formatNavControl(navAction.controlAction) | ||
else -> null | ||
} | ||
} | ||
|
||
|
||
fun formatTime(dateTime: ZonedDateTime?): String? { | ||
return dateTime?.toLocalTime()?.toString()?.padStart(5, '0') ?: "N/A" | ||
} | ||
|
||
|
||
fun formatEnvControl(action: EnvActionControlEntity?): String? { | ||
return action?.let { | ||
val startTime = formatTime(action.actionStartDateTimeUtc) | ||
val endTime = formatTime(action.actionEndDateTimeUtc) | ||
val facade = action.facade?.let { " - $it" } ?: "" | ||
val themes = action.themes?.let { " - ${it.map { theme -> theme.theme }.joinToString(" + ")}" } ?: "" | ||
val amountOfControls = action.actionNumberOfControls?.let { " - $it contrôles" } ?: "" | ||
return "$startTime / $endTime - Contrôle Environnement$facade$themes$amountOfControls" | ||
} | ||
} | ||
|
||
fun formatFishControl(action: MissionAction?): String? { | ||
return action?.let { | ||
val startTime = formatTime(action.actionDatetimeUtc) | ||
val coords = "${action.latitude ?: "N/A"}/${action.longitude ?: "N/A"}" | ||
val vesselInfo = "${action.vesselName ?: "N/A"} - ${action.vesselId}" | ||
val seizureAndDiversion = action.seizureAndDiversion?.let { " - retour du navire au port" } ?: "" | ||
val natinfs: String = listOf( | ||
action.gearInfractions.map { it.natinf.toString() }, | ||
action.logbookInfractions.map { it.natinf.toString() }, | ||
action.speciesInfractions.map { it.natinf.toString() }, | ||
action.otherInfractions.map { it.natinf.toString() } | ||
).flatten().distinct().let { list -> | ||
if (list.isEmpty()) { | ||
" - RAS" | ||
} else { | ||
" - NATINF: ${list.joinToString(" + ")}" | ||
} | ||
} | ||
val pvCount = listOf( | ||
action.gearInfractions.map { it.infractionType }, | ||
action.logbookInfractions.map { it.infractionType }, | ||
action.speciesInfractions.map { it.infractionType }, | ||
action.otherInfractions.map { it.infractionType } | ||
).flatten().count { it == InfractionType.WITH_RECORD } | ||
val pv = if (pvCount > 0) "avec PV" else "sans PV" | ||
|
||
val species = if (action.speciesOnboard.isNotEmpty()) { | ||
"Espèces contrôlées: " + action.speciesOnboard.joinToString(" - ") { "${it.speciesCode}: ${it.controlledWeight ?: "N/A"}/${it.declaredWeight ?: "N/A"} kg" } | ||
} else { | ||
"Espèces contrôlées: N/A" | ||
} | ||
|
||
return "$startTime - Contrôle Pêche - $coords - $vesselInfo - $species - Infractions: $pv$natinfs$seizureAndDiversion" | ||
} | ||
} | ||
|
||
fun formatNavNote(action: ActionFreeNoteEntity?): String? { | ||
return action?.let { | ||
val startTime = formatTime(action.startDateTimeUtc) | ||
val observation = action.observations ?: "" | ||
return "$startTime - $observation" | ||
} | ||
} | ||
|
||
|
||
fun formatNavStatus(action: ActionStatusEntity?): String? { | ||
return action?.let { | ||
val startTime = formatTime(action.startDateTimeUtc) | ||
val status = mapActionStatusTypeToHumanString(action.status) | ||
val observation = action.observations?.let { "- $it" } ?: "" | ||
return "$startTime - $status - début $observation" | ||
} | ||
} | ||
|
||
fun formatNavControl(action: ActionControlEntity?): String? { | ||
return action?.let { | ||
val startTime = formatTime(action.startDateTimeUtc) | ||
val endTime = formatTime(action.endDateTimeUtc) | ||
val vesselIdentifier = action.vesselIdentifier?.let { "- $it" } ?: "" | ||
return "$startTime / $endTime - Contrôle administratif $vesselIdentifier" | ||
} | ||
} | ||
} |
Oops, something went wrong.