diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index 56c2ad3540..383cab5393 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -928,7 +928,8 @@ Creating orders during order generation and is not respected automatically when the order changes later.) * ``force`` (optional). If set to ``true``, quotas will be ignored. - * ``send_mail`` (optional). If set to ``true``, the same emails will be sent as for a regular order. Defaults to + * ``send_mail`` (optional). If set to ``true``, the same emails will be sent as for a regular order, regardless of + whether these emails are enabled for certain sales channels. Defaults to ``false``. If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually diff --git a/doc/spelling_wordlist.txt b/doc/spelling_wordlist.txt index ba0b0918d7..67f0f50b03 100644 --- a/doc/spelling_wordlist.txt +++ b/doc/spelling_wordlist.txt @@ -47,6 +47,7 @@ gunicorn guid hardcoded hostname +ics idempotency iframe incrementing diff --git a/doc/user/events/email.rst b/doc/user/events/email.rst index 69deafeb93..01225a1121 100644 --- a/doc/user/events/email.rst +++ b/doc/user/events/email.rst @@ -26,6 +26,9 @@ Sender address we strongly recommend to use the SMTP settings below as well, otherwise your e-mails might be detected as spam due to the `Sender Policy Framework`_ and similar mechanisms. +Sender name + This is the name associated with the sender address. By default, this is your event name. + Signature This text will be appended to all e-mails in form of a signature. This might be useful e.g. to add your contact details or any legal information that needs to be included with the e-mails. @@ -33,6 +36,15 @@ Signature Bcc address This email address will receive a copy of every event-related email. +Attach calendar files + With this option, every order confirmation mail will include an ics file with name, date and location of + your event. It can be imported into many digital calendars. + +Sales Channels for Checkout Emails + When you are using multiple sales channel, you may want to decide that mails for order and payment confirmation + are only to be sent for some sales channels. For orders created through the default online shop, these emails + must always be send. A similar option is available for ticket download reminders. + E-mail design ------------- diff --git a/src/pretix/base/migrations/0159_mails_by_sales_channel.py b/src/pretix/base/migrations/0159_mails_by_sales_channel.py new file mode 100644 index 0000000000..efab29c1b0 --- /dev/null +++ b/src/pretix/base/migrations/0159_mails_by_sales_channel.py @@ -0,0 +1,39 @@ +# Generated by Django 3.0.8 on 2020-07-24 09:05 + +from django.db import migrations + +from pretix.base.channels import get_all_sales_channels + +def set_sales_channels(apps, schema_editor): + # We now allow restricting some mails to certain sales channels + # The default is changing from all channels to "web" only + # Therefore, for existing events, we enable all sales channels + Event_SettingsStore = apps.get_model('pretixbase', 'Event_SettingsStore') + Event = apps.get_model('pretixbase', 'Event') + all_sales_channels = "[" + ", ".join('"' + sc + '"' for sc in get_all_sales_channels()) + "]" + batch_size = 1000 + Event_SettingsStore.objects.bulk_create([ + Event_SettingsStore( + object=event, + key="mail_sales_channel_placed_paid", + value=all_sales_channels) + for event in Event.objects.all() + ], batch_size=batch_size) + Event_SettingsStore.objects.bulk_create([ + Event_SettingsStore( + object=event, + key="mail_sales_channel_download_reminder", + value=all_sales_channels) + for event in Event.objects.all() + ], batch_size=batch_size) + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0158_auto_20200724_0754'), + ] + + operations = [ + migrations.RunPython(set_sales_channels, migrations.RunPython.noop), + ] diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 4b62a0c9dc..8d64eac1dd 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -1491,7 +1491,7 @@ class OrderPayment(models.Model): trigger_pdf=not send_mail or not self.order.event.settings.invoice_email_attachment ) - if send_mail: + if send_mail and self.order.sales_channel in self.order.event.settings.mail_sales_channel_placed_paid: self._send_paid_mail(invoice, user, mail_text) if self.order.event.settings.mail_send_order_paid_attendee: for p in self.order.positions.all(): diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index a895dd0a88..bfc618ef5f 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -960,11 +960,12 @@ def _perform_order(event: Event, payment_provider: str, position_ids: List[str], email_attendees = event.settings.mail_send_order_placed_attendee email_attendees_template = event.settings.mail_text_order_placed_attendee - _order_placed_email(event, order, pprov, email_template, log_entry, invoice, payment) - if email_attendees: - for p in order.positions.all(): - if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email: - _order_placed_email_attendee(event, order, p, email_attendees_template, log_entry) + if sales_channel in event.settings.mail_sales_channel_placed_paid: + _order_placed_email(event, order, pprov, email_template, log_entry, invoice, payment) + if email_attendees: + for p in order.positions.all(): + if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email: + _order_placed_email_attendee(event, order, p, email_attendees_template, log_entry) return order.id @@ -1056,6 +1057,9 @@ def send_download_reminders(sender, **kwargs): if days is None: continue + if o.sales_channel not in event.settings.mail_sales_channel_download_reminder: + continue + reminder_date = (o.first_date - timedelta(days=days)).replace(hour=0, minute=0, second=0, microsecond=0) if now() < reminder_date or o.datetime > reminder_date: continue diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index a73b8823c3..cadd41c9f8 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -1190,6 +1190,14 @@ DEFAULTS = { "Defaults to your event name."), ) }, + 'mail_sales_channel_placed_paid': { + 'default': ['web'], + 'type': list, + }, + 'mail_sales_channel_download_reminder': { + 'default': ['web'], + 'type': list, + }, 'mail_text_signature': { 'type': LazyI18nString, 'default': "" diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index 350063623c..1861ef1c0b 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -1,5 +1,3 @@ -from urllib.parse import urlencode, urlparse - from django import forms from django.conf import settings from django.core.exceptions import ValidationError @@ -17,6 +15,7 @@ from i18nfield.forms import ( I18nForm, I18nFormField, I18nFormSetMixin, I18nTextarea, I18nTextInput, ) from pytz import common_timezones, timezone +from urllib.parse import urlencode, urlparse from pretix.base.channels import get_all_sales_channels from pretix.base.email import get_available_placeholders @@ -750,6 +749,11 @@ def multimail_validate(val): return s +def contains_web_channel_validate(val): + if "web" not in val: + raise ValidationError(_("The online shop must be selected to receive these emails.")) + + class MailSettingsForm(SettingsForm): auto_fields = [ 'mail_prefix', @@ -758,6 +762,27 @@ class MailSettingsForm(SettingsForm): 'mail_attach_ical', ] + mail_sales_channel_placed_paid = forms.MultipleChoiceField( + choices=lambda: [(ident, sc.verbose_name) for ident, sc in get_all_sales_channels().items()], + label=_('Sales channels for checkout emails'), + help_text=_('The order placed and paid emails will only be send to orders from these sales channels. ' + 'The online shop must be enabled.'), + widget=forms.CheckboxSelectMultiple( + attrs={'class': 'scrolling-multiple-choice'} + ), + validators=[contains_web_channel_validate], + ) + + mail_sales_channel_download_reminder = forms.MultipleChoiceField( + choices=lambda: [(ident, sc.verbose_name) for ident, sc in get_all_sales_channels().items()], + label=_('Sales channels'), + help_text=_('This email will only be send to orders from these sales channels. The online shop must be enabled.'), + widget=forms.CheckboxSelectMultiple( + attrs={'class': 'scrolling-multiple-choice'} + ), + validators=[contains_web_channel_validate], + ) + mail_bcc = forms.CharField( label=_("Bcc address"), help_text=_("All emails will be sent to this address as a Bcc copy"), diff --git a/src/pretix/control/templates/pretixcontrol/event/mail.html b/src/pretix/control/templates/pretixcontrol/event/mail.html index 0988ebaccc..0ea2e13ddf 100644 --- a/src/pretix/control/templates/pretixcontrol/event/mail.html +++ b/src/pretix/control/templates/pretixcontrol/event/mail.html @@ -17,6 +17,7 @@ {% bootstrap_field form.mail_text_signature layout="control" %} {% bootstrap_field form.mail_bcc layout="control" %} {% bootstrap_field form.mail_attach_ical layout="control" %} + {% bootstrap_field form.mail_sales_channel_placed_paid layout="control" %}