Skip to content

Commit

Permalink
libraries: add notification settings in library definition
Browse files Browse the repository at this point in the history
* Adds notification settings in library jsonschema and mapping.
* Adds notification settings data.
* For patron with mail communication channel the notification is sent to
  the corresponding library email if it exists.
* Closes rero#913.
* Adds patron information for each email sent to the library emails.

Co-Authored-by: Alicia Zangger <alicia.zangger@rero.ch>
Co-Authored-by: Renaud Michotte <renaud.michotte@gmail.com>
Co-Authored-by: Johnny Mariéthoz <johnny.mariethoz@rero.ch>
  • Loading branch information
3 people committed Mar 16, 2021
1 parent eba815d commit 9ad6be9
Show file tree
Hide file tree
Showing 28 changed files with 736 additions and 113 deletions.
352 changes: 352 additions & 0 deletions data/libraries.json

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions rero_ils/modules/libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,16 @@ def get_timezone(self):
default = pytz.timezone('Europe/Zurich')
return default

def email_notification_type(self, notification_type):
"""Get the email corresponding to the given notification type.
:param notification_type: the notification type.
:return: the email corresponding to the notification type.
:rtype: string
"""
for setting in self['notification_settings']:
if setting['type'] == notification_type:
return setting['email']

class LibrariesIndexer(IlsRecordsIndexer):
"""Holdings indexing class."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,62 @@
"name",
"organisation"
],
"definitions": {
"default_notification_setting": {
"additionalProperties": false,
"required": [
"type",
"email"
],
"properties": {
"type": {
"type": "string",
"enum": [
"due_soon",
"recall",
"overdue"
]
},
"email": {
"title": "E-mail",
"description": "The notifications for patrons without e-mail are sent to this address. No notification is sent if the field is empty.",
"type": "string",
"format": "email",
"pattern": "^.*@.*\\..+$",
"minLength": 6
}
}
},
"availability_notification_setting": {
"additionalProperties": false,
"required": [
"type",
"email",
"delay"
],
"properties": {
"type": {
"type": "string",
"const": "availability"
},
"email": {
"title": "E-mail",
"description": "The notifications for patrons without e-mail are sent to this address. No notification is sent if the field is empty.",
"type": "string",
"format": "email",
"pattern": "^.*@.*\\..+$",
"minLength": 6
},
"delay": {
"title": "Delay in minutes",
"description": "Sending how many minutes after the item is available.",
"type": "number",
"minimum": 0,
"default": 0
}
}
}
},
"properties": {
"$schema": {
"title": "Schema",
Expand Down Expand Up @@ -261,6 +317,21 @@
}
}
}
},
"notification_settings": {
"title": "Notification settings",
"type": "array",
"minItems": 1,
"items": {
"oneOf": [
{
"$ref": "#/definitions/default_notification_setting"
},
{
"$ref": "#/definitions/availability_notification_setting"
}
]
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@
}
}
},
"notification_settings": {
"properties": {
"type": {
"type": "keyword"
},
"email": {
"type": "keyword"
},
"delay": {
"type": "integer"
}
}
},
"organisation": {
"properties": {
"type": {
Expand Down
7 changes: 6 additions & 1 deletion rero_ils/modules/loans/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,12 @@ def create_notification(self, notification_type=None, counter=0):
}
notification = Notification.create(
data=record, dbcommit=True, reindex=True)
return notification.dispatch()
enqueue = notification_type not in [
Notification.RECALL_NOTIFICATION_TYPE,
Notification.AVAILABILITY_NOTIFICATION_TYPE
]
# put into the queue only for batch notifications i.e. overdue
return notification.dispatch(enqueue=enqueue)

@classmethod
def concluded(cls, loan):
Expand Down
89 changes: 60 additions & 29 deletions rero_ils/modules/notifications/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def not_yet_implemented(*args):
if notification:
data = notification.replace_pids_and_refs()
communication_switcher = {
'email': Dispatcher.send_mail,
'email': Dispatcher.send_mail_to_patron,
'mail': Dispatcher.send_mail_for_printing,
# 'sms': not_yet_implemented
# 'telepathy': self.madness_mind
# ...
Expand Down Expand Up @@ -72,43 +73,73 @@ def not_yet_implemented(*args):
return notification

@staticmethod
def send_mail(data):
"""Send the notification by email."""
def _create_email(data, patron, library, recipients):
"""."""
from flask_babelex import Locale

from .api import get_template_to_use
from ..loans.api import Loan

language = patron['patron']['communication_language']
# set the current language for translations in template
with current_app.test_request_context() as ctx:
ctx.babel_locale = Locale.parse(language)
loan = Loan.get_record_by_pid(data['loan']['pid'])
tpl_path = get_template_to_use(loan, data).rstrip('/')
template = '{tpl_path}/{language}.txt'.format(
tpl_path=tpl_path,
language=language
)
# get the sender email from
# loan.pickup_location_pid.location.library.email
sender = library['email']
msg = TemplatedMessage(
template_body=template,
sender=sender,
recipients=recipients,
ctx=data['loan']
)
text = msg.body.split('\n')
# subject is the first line
msg.subject = text[0]
# body
msg.body = '\n'.join(text[1:])
return msg

@staticmethod
def send_mail_for_printing(data):
"""Send the notification by email."""
patron = data['loan']['patron']
# get the recipient email from loan.patron.patron.email
recipient = patron.get('email')
# do nothing if the patron does not have an email
if not recipient:
library = Location.get_record_by_pid(
data['loan']['pickup_location_pid']).get_library()
# get the recipient email from the library
email = library.email_notification_type(data['notification_type'])
if not email:
current_app.logger.warning(
'Patron (pid: {pid}) does not have an email'.format(
'Notification is lost for patron(pid).'.format(
pid=patron['pid']))
return
language = patron['patron']['communication_language']
loan = Loan.get_record_by_pid(data['loan']['pid'])
tpl_path = get_template_to_use(loan, data).rstrip('/')
template = '{tpl_path}/{language}.txt'.format(
tpl_path=tpl_path,
language=language
)
msg = Dispatcher._create_email(data, patron, library, [email])
task_send_email.delay(msg.__dict__)

# get the sender email from
# loan.pickup_location_pid.location.library.email
@staticmethod
def send_mail_to_patron(data):
"""Send the notification by email to the patron."""
patron = data['loan']['patron']
library = Location.get_record_by_pid(
data['loan']['pickup_location_pid']).get_library()
sender = library['email']
msg = TemplatedMessage(
template_body=template,
sender=sender,
recipients=[recipient],
ctx=data['loan']
)
# get the recipient email from loan.patron.patron.email
recipients = [patron.get('email')]
# additional recipient
add_recipient = patron['patron'].get('additional_communication_email')
if add_recipient:
msg.add_recipient(add_recipient)
text = msg.body.split('\n')
msg.subject = text[0]
msg.body = '\n'.join(text[1:])
task_send_email.run(msg.__dict__)
recipents.push(add_recipient)
# delay
delay_availability = 0
# get notification settings for notification type
notification_type = data['notification_type']
for setting in library['notification_settings']:
if setting['type'] == 'availability':
delay_availability = setting['delay']
msg = Dispatcher._create_email(data, patron, library, recipients)
task_send_email.apply_async((msg.__dict__,), countdown=delay_availability)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{%- if patron.patron.communication_channel == 'mail' %}
{{ patron.first_name }} {{ patron.last_name }}
{% if patron.street %}{{ patron.street }}{% endif %}
{% if patron.postal_code %}{{ patron.postal_code }}{% endif %} {% if patron.city %}{{ patron.city }}{% endif %}
{% if patron.country %}{{ _('country_'+patron.country) }}{% endif %}


{% endif -%}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Invitation to pick up a document
{%- include('email/_patron_address.txt') %}
Dear patron,

The document you requested is now available. You can pick it up at the loan desk of the library mentioned below.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Invitation à retirer un document
{%- include('email/_patron_address.txt') %}
Chère lectrice, cher lecteur,

Le document que vous avez demandé est maintenant disponible. Vous pouvez venir le retirer au bureau de prêt de la bibliothèque mentionnée ci-dessous.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Abholeinladung
{%- include('email/_patron_address.txt') %}
Sehr geehrte Leserin, sehr geehrter Leser,

Das von Ihnen bestellte Dokument ist nun verfügbar und kann an der Ausleihtheke der nachstehend genannten Bibliothek abgeholt werden.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Invito a ritirare un documento
{%- include('email/_patron_address.txt') %}
Cara lettrice, caro lettore,

Il documento che Lei ha domandato è ora disponibile. Lei può ritirarlo al servizio prestiti della biblioteca sotto indicata.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Expiry notice
{%- include('email/_patron_address.txt') %}
Dear patron,

The loan period of following documents is expiring:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

Avis d'échéance
{%- include('email/_patron_address.txt') %}
Chère lectrice, cher lecteur,

Le délai de prêt des documents mentionnés ci-dessous arrive à échéance :
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Ablauf der Ausleihfrist
{%- include('email/_patron_address.txt') %}
Sehr geehrte Leserin, sehr geehrter Leser,

Die Ausleihfrist der folgenden Dokumente läuft ab:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Avviso di scadenza
{%- include('email/_patron_address.txt') %}
Cara lettrice, caro lettore,

La durata di prestito dei seguenti documenti sta per scadere:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
The item [{{ item.barcode }}] has been requested
{%- include('email/_patron_address.txt') %}
An item has been requested. See below for information about this item.

Pickup location : {{ pickup_location.library.name }} -- {{ pickup_location.name }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
1st reminder
{% include('email/_patron_address.txt') %}
Dear patron,

The loan period of following documents has expired:

Title: {{ document.title_text }} / {{ document.responsibility_statement }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1er rappel
{%- include('email/_patron_address.txt') %}
Chère lectrice, cher lecteur,

La durée du prêt des documents mentionnés ci-dessous est échue :
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1. Mahnung
{%- include('email/_patron_address.txt') %}
Sehr geehrte Leserin, sehr geehrter Leser,

Die Ausleihfrist folgender Dokumente ist abgelaufen:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1° richiamo
{%- include('email/_patron_address.txt') %}
Cara lettrice, caro lettore,

La durata di prestito dei seguenti documenti è scaduta:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Non-extendable document
{%- include('email/_patron_address.txt') %}
Dear patron,

The document you borrowed has been requested by another person. An extension of the loan period is therefore no longer possible and we kindly ask you to return it at the latest by the due date.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{%- include('email/_patron_address.txt') %}
Document non prolongeable
Chère lectrice, cher lecteur,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Nicht verlängerbares Dokument
{%- include('email/_patron_address.txt') %}
Sehr geehrte Leserin, sehr geehrter Leser,

Das von Ihnen ausgeliehene Dokument ist von einer anderen Person reserviert worden. Eine Verlängerung der Ausleihfrist ist deshalb nicht mehr möglich und wir bitten Sie, das Dokument spätestens bis zum Rückgabedatum zurückzugeben.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Documento non prorogabile
{%- include('email/_patron_address.txt') %}
Cara lettrice, caro lettore,

Il documento che Lei ha presto in prestito è stato riservato da un'altra persona. Una proroga della durata di prestito non è quindi più possibile e La preghiamo di restituirlo entro la scadenza.
Expand Down
Loading

0 comments on commit 9ad6be9

Please sign in to comment.