chrono/chrono/agendas/management/commands/send_booking_reminders.py

78 lines
3.1 KiB
Python

# chrono - agendas system
# Copyright (C) 2020 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime, timedelta
import pytz
from django.conf import settings
from django.core.management.base import BaseCommand
from django.db.models import F
from django.utils import translation
from chrono.agendas.models import Booking
from chrono.utils import timezone
from .utils import send_reminder
SENDING_IN_PROGRESS = datetime(year=2, month=1, day=1, tzinfo=pytz.UTC)
class Command(BaseCommand):
help = 'Send booking reminders'
def handle(self, **options):
translation.activate(settings.LANGUAGE_CODE)
for msg_type in ('email', 'sms'):
self.notify(msg_type)
def notify(self, msg_type):
# We want to send reminders x days before event starts, say x=2. For
# that we look at events that begin no earlier than 2 days minus 6
# hours from now, AND no later than 2 days. Hence an event that is in 2
# days will only be in this range from exactly 2 days before to 2 days
# before plus 6 hours. In case command is ran once every hour and a
# sending fails, this allows 6 retries before giving up.
reminder_delta = F(f'event__agenda__reminder_settings__days_before_{msg_type}') * timedelta(1)
starts_before = timezone.now() + reminder_delta
starts_after = timezone.now() + reminder_delta - timedelta(hours=6)
# prevent user who just booked from getting a reminder (also documented in a help_text)
created_before = timezone.now() - timedelta(hours=12)
bookings = Booking.objects.filter(
cancellation_datetime__isnull=True,
creation_datetime__lte=created_before,
event__start_datetime__lte=starts_before,
event__start_datetime__gte=starts_after,
in_waiting_list=False,
**{f'{msg_type}_reminder_datetime__isnull': True},
).select_related('event', 'event__agenda', 'event__agenda__reminder_settings')
bookings_list = list(bookings.order_by('pk'))
bookings_pk = list(bookings.values_list('pk', flat=True))
bookings.update(**{f'{msg_type}_reminder_datetime': SENDING_IN_PROGRESS})
try:
for booking in bookings_list:
send_reminder(booking, msg_type)
finally:
Booking.objects.filter(
pk__in=bookings_pk, **{f'{msg_type}_reminder_datetime': SENDING_IN_PROGRESS}
).update(
**{f'{msg_type}_reminder_datetime': None},
)