Skip to content

Commit

Permalink
Notifier les avaries des navires ayant une balise UNSUPERVISED (#2761)
Browse files Browse the repository at this point in the history
## Linked issues

- Resolve #2751
- [x] Rajouter les nouveaux enum dans les testdata backend
- [x] Il faut rajouter les enums dans le backend et le frontend car une
balise peut changer de statut et passer de `UNSUPERVISED` à `ACTIVATED`
pendant qu'elle est en avarie, auquel cas l'avarie deviendra visible
dans le front et l'utilisateur pourra cliquer dessus et visualiser les
noficitations envoyées, y compris celles de type `*UNSUPERVISED_BEACON`
envoyées avant le changement de statut de la balise
  • Loading branch information
louptheron committed Dec 13, 2023
2 parents 2b10414 + 56d0e56 commit 5ecaee2
Show file tree
Hide file tree
Showing 25 changed files with 433 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ enum class BeaconMalfunctionNotificationType {
MALFUNCTION_AT_PORT_REMINDER,
END_OF_MALFUNCTION,
MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC,
MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON,
MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ALTER TYPE public.beacon_malfunction_notification_type
ADD VALUE 'MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON'
AFTER 'MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC';

ALTER TYPE public.beacon_malfunction_notification_type
ADD VALUE 'MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON'
AFTER 'MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON';
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ VALUES (1, 'FAK000999999', 'CALLME', 'DONTSINK', 'GB', 'INTERNAL_REFERENCE_NUMBE
null, 9, null, 'PO8U9U4', 'UNSUPERVISED'),
(11, null, 'IJU5217', 'EJ600773', 'FR', 'INTERNAL_REFERENCE_NUMBER', 'VESSEL WITHOUT CFR',
'AT_PORT', 'INITIAL_ENCOUNTER', NOW() - ('2 WEEKS 2 DAYS')::interval, null, NOW() - ('2 WEEK 2 DAYS')::interval,
null, 9, null, 'PO8U9U4', 'UNSUPERVISED'),
(12, null, 'IJU5217', 'EJ600773', 'FR', 'INTERNAL_REFERENCE_NUMBER', 'VESSEL WITHOUT CFR',
'AT_PORT', 'INITIAL_ENCOUNTER', NOW() - ('2 WEEKS 1 DAY')::interval, null, NOW() - ('2 WEEK 1 DAYS')::interval,
null, 9, null, 'PO8U9U4', 'UNSUPERVISED');
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ VALUES (1, 2, NOW() - INTERVAL '7 weeks 18 hours', 'MALFUNCTION_AT_SEA_INITIAL_N
(9, 2, NOW() - INTERVAL '5 weeks 6 days 23 hours 55 minutes', 'END_OF_MALFUNCTION', 'EMAIL', 'VESSEL_OPERATOR',
'LE PELETIER', 'lepeletier@gmail.com', false, 'The server didn''t reply properly to the helo greeting.'),
(10, 2, NOW() - INTERVAL '5 weeks 6 days 23 hours 55 minutes', 'END_OF_MALFUNCTION', 'SMS', 'VESSEL_CAPTAIN',
NULL, '0600000000', null, null);
NULL, '0600000000', null, null),
(11, 12, NOW() - INTERVAL '1 weeks 6 days 23 hours 55 minutes', 'MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC', 'EMAIL', 'VESSEL_CAPTAIN',
NULL, 'unemail@hotmail.fr', null, null);
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class JpaBeaconMalfunctionsRepositoryITests : AbstractDBTests() {
// When
val baconMalfunctions = jpaBeaconMalfunctionsRepository.findAll()

assertThat(baconMalfunctions).hasSize(11)
assertThat(baconMalfunctions).hasSize(12)
assertThat(baconMalfunctions.first().internalReferenceNumber).isEqualTo("FAK000999999")
assertThat(baconMalfunctions.first().stage).isEqualTo(Stage.INITIAL_ENCOUNTER)
assertThat(baconMalfunctions.first().vesselStatus).isEqualTo(VesselStatus.ACTIVITY_DETECTED)
Expand All @@ -35,7 +35,7 @@ class JpaBeaconMalfunctionsRepositoryITests : AbstractDBTests() {
// When
val baconMalfunctions = jpaBeaconMalfunctionsRepository.findAllExceptArchived()

assertThat(baconMalfunctions).hasSize(10)
assertThat(baconMalfunctions).hasSize(11)
assertThat(baconMalfunctions.first().internalReferenceNumber).isEqualTo("FAK000999999")
assertThat(baconMalfunctions.first().stage).isEqualTo(Stage.INITIAL_ENCOUNTER)
assertThat(baconMalfunctions.first().vesselStatus).isEqualTo(VesselStatus.ACTIVITY_DETECTED)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends "base_template.jinja" %}
{% block message %}
{% block beginning %}
<p>Nous vous informons que <strong>le CNSP ne reçoit pas les positions de votre navire par le
système de surveillance satellitaire des navires (VMS).
{% if last_position_latitude and last_position_longitude and last_position_datetime_utc %}
</strong>La dernière position reçue date du {{ last_position_datetime_utc }},
latitude {{ last_position_latitude }}, longitude {{ last_position_longitude }}.
{%endif%}
</p>
{% endblock %}

<p>Si l'absence d'émission est liée à un problème technique, veuillez contacter votre installateur ou votre
opérateur satellitaire pour régler le problème.</p>

<p>Pour rappel, <strong>votre navire n'est pas autorisé à reprendre la
mer tant que votre installation VMS n'est pas en état de fonctionnement*.</strong></p>

<p>Le non-respect de ces obligations peut être sanctionné par une amende de 22 500€**.</p>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends "base_template.jinja" %}
{% block message %}
{% block beginning %}
<p>Nous vous informons que <strong>le CNSP ne reçoit pas les positions de votre navire par le
système de surveillance satellitaire des navires (VMS).</strong>
{% if last_position_latitude and last_position_longitude and last_position_datetime_utc %}
La dernière position reçue date du {{ last_position_datetime_utc }},
latitude {{ last_position_latitude }}, longitude {{ last_position_longitude }}.
{%endif%}
</p>

<p>Veuillez contacter votre installateur ou votre opérateur satellitaire pour régler le problème.</p>
{% endblock %}

<p>Le CNSP vous informera de la reprise de réception des positions de votre navire.</p>

<p>Pour rappel, au terme de votre marée, <strong>votre navire ne sera pas autorisé à reprendre la
mer tant que votre installation VMS ne sera pas en état de fonctionnement*.</strong></p>
<p>Le non-respect de ces obligations peut être sanctionné par une amende de 22 500€**.</p>
{% endblock %}
15 changes: 8 additions & 7 deletions datascience/src/pipeline/entities/beacon_malfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,27 @@ class EndOfMalfunctionReason(Enum):

class BeaconMalfunctionNotificationType(Enum):
MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION = "MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION"
MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON = (
"MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON"
)
MALFUNCTION_AT_SEA_REMINDER = "MALFUNCTION_AT_SEA_REMINDER"
MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION = (
"MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION"
)
MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON = (
"MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON"
)
MALFUNCTION_AT_PORT_REMINDER = "MALFUNCTION_AT_PORT_REMINDER"
END_OF_MALFUNCTION = "END_OF_MALFUNCTION"
MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC = "MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC"

def to_notification_subject_template(self):
type_subject_mapping = {
"MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION": "{vessel_name} ({immat}) : interruption en mer des émissions VMS",
"MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON": "{vessel_name} ({immat}) : interruption en mer des émissions VMS",
"MALFUNCTION_AT_SEA_REMINDER": "{vessel_name} ({immat}) : RAPPEL : interruption en mer des émissions VMS",
"MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION": "{vessel_name} ({immat}) : interruption à quai des émissions VMS",
"MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON": "{vessel_name} ({immat}) : interruption à quai des émissions VMS",
"MALFUNCTION_AT_PORT_REMINDER": "{vessel_name} ({immat}) : RAPPEL : interruption à quai des émissions VMS",
"END_OF_MALFUNCTION": "{vessel_name} ({immat}) : reprise des émissions VMS",
"MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC": "Interruption of VMS transmissions from fishing vessel {vessel_name} ({immat})",
Expand Down Expand Up @@ -129,9 +137,7 @@ def __post_init__(self):
)

def get_sms_addressees(self) -> List[BeaconMalfunctionNotificationAddressee]:

if not self.test_mode:

addressees = []

if self.vessel_mobile_phone:
Expand Down Expand Up @@ -167,9 +173,7 @@ def get_sms_addressees(self) -> List[BeaconMalfunctionNotificationAddressee]:
return addressees

def get_fax_addressees(self) -> List[BeaconMalfunctionNotificationAddressee]:

if not self.test_mode:

addressees = []

if self.vessel_fax:
Expand Down Expand Up @@ -205,9 +209,7 @@ def get_fax_addressees(self) -> List[BeaconMalfunctionNotificationAddressee]:
return addressees

def get_email_addressees(self) -> List[BeaconMalfunctionNotificationAddressee]:

if not self.test_mode:

vessel_emails = self.vessel_emails if self.vessel_emails else []
satellite_operator_emails = (
self.satellite_operator_emails if self.satellite_operator_emails else []
Expand Down Expand Up @@ -307,7 +309,6 @@ class BeaconMalfunctionMessageToSend:
communication_means: CommunicationMeans

def get_addressees(self) -> List[BeaconMalfunctionNotificationAddressee]:

if self.communication_means is CommunicationMeans.EMAIL:
return self.beacon_malfunction_to_notify.get_email_addressees()
elif self.communication_means is CommunicationMeans.SMS:
Expand Down
31 changes: 20 additions & 11 deletions datascience/src/pipeline/flows/notify_beacon_malfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def to_malfunctions_to_notify_list(

@task(checkpoint=False)
def get_templates() -> dict:

templates_locations = [
EMAIL_TEMPLATES_LOCATION / "beacon_malfunctions",
EMAIL_STYLESHEETS_LOCATION,
Expand All @@ -87,9 +86,19 @@ def get_templates() -> dict:
BeaconMalfunctionNotificationType.MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION: (
env.get_template("malfunction_at_sea_initial_notification.jinja")
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON: (
env.get_template(
"malfunction_at_sea_initial_notification_unsupervised_beacon.jinja"
)
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION: (
env.get_template("malfunction_at_port_initial_notification.jinja")
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON: (
env.get_template(
"malfunction_at_port_initial_notification_unsupervised_beacon.jinja"
)
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_SEA_REMINDER: (
env.get_template("malfunction_at_sea_reminder.jinja")
),
Expand All @@ -109,7 +118,6 @@ def get_templates() -> dict:

@task(checkpoint=False)
def get_sms_templates() -> dict:

env = Environment(
loader=FileSystemLoader(SMS_TEMPLATES_LOCATION), autoescape=select_autoescape()
)
Expand All @@ -118,9 +126,19 @@ def get_sms_templates() -> dict:
BeaconMalfunctionNotificationType.MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION: (
env.get_template("malfunction_at_sea_initial_notification.jinja")
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_SEA_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON: (
env.get_template(
"malfunction_initial_notification_unsupervised_beacon.jinja"
)
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION: (
env.get_template("malfunction_at_port_initial_notification.jinja")
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_PORT_INITIAL_NOTIFICATION_UNSUPERVISED_BEACON: (
env.get_template(
"malfunction_initial_notification_unsupervised_beacon.jinja"
)
),
BeaconMalfunctionNotificationType.MALFUNCTION_AT_SEA_REMINDER: (
env.get_template("malfunction_at_sea_reminder.jinja")
),
Expand All @@ -139,7 +157,6 @@ def get_sms_templates() -> dict:
def render(
m: BeaconMalfunctionToNotify, templates: dict, output_format: str = "html"
) -> Union[str, bytes]:

try:
assert output_format in ("html", "pdf")
except AssertionError:
Expand Down Expand Up @@ -211,7 +228,6 @@ def render(

@task(checkpoint=False)
def render_sms(m: BeaconMalfunctionToNotify, templates: dict) -> str:

if (
m.notification_type
is BeaconMalfunctionNotificationType.MALFUNCTION_NOTIFICATION_TO_FOREIGN_FMC
Expand Down Expand Up @@ -253,7 +269,6 @@ def render_sms(m: BeaconMalfunctionToNotify, templates: dict) -> str:
def create_email(
html: str, pdf: bytes, m: BeaconMalfunctionToNotify
) -> BeaconMalfunctionMessageToSend:

to = [
email_addressee.address_or_number
for email_addressee in m.get_email_addressees()
Expand Down Expand Up @@ -285,7 +300,6 @@ def create_email(
def create_sms(
text: str, m: BeaconMalfunctionToNotify
) -> BeaconMalfunctionMessageToSend:

to = [sms_addressee.address_or_number for sms_addressee in m.get_sms_addressees()]

if to:
Expand All @@ -302,7 +316,6 @@ def create_sms(
def create_fax(
pdf: bytes, m: BeaconMalfunctionToNotify
) -> BeaconMalfunctionMessageToSend:

to = [fax_addressee.address_or_number for fax_addressee in m.get_fax_addressees()]

if to:
Expand Down Expand Up @@ -438,7 +451,6 @@ def send_beacon_malfunction_message(
notifications = []

for addressee in addressees:

if addressee.address_or_number in send_errors:
success = False
error_message = send_errors[addressee.address_or_number][1]
Expand Down Expand Up @@ -485,7 +497,6 @@ def make_reset_requested_notifications_statement(
beacon_malfunctions_table: Table,
notified_malfunctions: List[BeaconMalfunctionToNotify],
) -> sqlalchemy.sql.dml.Update:

beacon_malfunction_ids_to_reset = [
n.beacon_malfunction_id for n in notified_malfunctions
]
Expand All @@ -509,10 +520,8 @@ def execute_statement(reset_requested_notifications_statement):


with Flow("Notify malfunctions", executor=LocalDaskExecutor()) as flow:

flow_not_running = check_flow_not_running()
with case(flow_not_running, True):

test_mode = Parameter("test_mode")
is_integration = Parameter("is_integration")

Expand Down
Loading

0 comments on commit 5ecaee2

Please sign in to comment.