From 73776ce0dde430e8cfde53b3a26f39bf72582cac Mon Sep 17 00:00:00 2001 From: Phin Wolkwitz Date: Mon, 24 Apr 2023 13:31:03 +0200 Subject: [PATCH] Order approval: Add attendee mail settings (Z#23114617, Z#23118978) (#3234) Co-authored-by: Raphael Michel --- src/pretix/base/services/orders.py | 19 ++++++ src/pretix/base/settings.py | 40 ++++++++++++ src/pretix/control/forms/event.py | 36 +++++++++++ .../templates/pretixcontrol/event/mail.html | 2 +- src/tests/base/test_orders.py | 64 ++++++++++++++++++- 5 files changed, 159 insertions(+), 2 deletions(-) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index dd41d5cc73..301c4e135c 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -391,9 +391,15 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None, force=False if order.total == Decimal('0.00'): email_template = order.event.settings.mail_text_order_approved_free email_subject = order.event.settings.mail_subject_order_approved_free + email_attendees = order.event.settings.mail_send_order_approved_free_attendee + email_attendee_template = order.event.settings.mail_text_order_approved_free_attendee + email_attendee_subject = order.event.settings.mail_subject_order_approved_free_attendee else: email_template = order.event.settings.mail_text_order_approved email_subject = order.event.settings.mail_subject_order_approved + email_attendees = order.event.settings.mail_send_order_approved_attendee + email_attendee_template = order.event.settings.mail_text_order_approved_attendee + email_attendee_subject = order.event.settings.mail_subject_order_approved_attendee email_context = get_email_context(event=order.event, order=order) try: @@ -406,6 +412,19 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None, force=False except SendMailException: logger.exception('Order approved email could not be sent') + 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: + email_attendee_context = get_email_context(event=order.event, order=order, position=p) + try: + p.send_mail( + email_attendee_subject, email_attendee_template, email_attendee_context, + 'pretix.event.order.email.order_approved', user, + attach_tickets=True, + ) + except SendMailException: + logger.exception('Order approved email could not be sent to attendee') + return order.pk diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 221ac26b7f..2dd2935520 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -2275,6 +2275,26 @@ You can select a payment method and perform the payment here: {url} +Best regards, +Your {event} team""")) + }, + 'mail_send_order_approved_attendee': { + 'type': bool, + 'default': 'False' + }, + 'mail_subject_order_approved_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(gettext_noop("Your event registration: {code}")), + }, + 'mail_text_order_approved_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(gettext_noop("""Hello, + +we approved a ticket ordered for you for {event}. + +You can view the details and status of your ticket here: +{url} + Best regards, Your {event} team""")) }, @@ -2292,6 +2312,26 @@ at our event. As you only ordered free products, no payment is required. You can change your order details and view the status of your order at {url} +Best regards, +Your {event} team""")) + }, + 'mail_send_order_approved_free_attendee': { + 'type': bool, + 'default': 'False' + }, + 'mail_subject_order_approved_free_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(gettext_noop("Your event registration: {code}")), + }, + 'mail_text_order_approved_free_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(gettext_noop("""Hello, + +we approved a ticket ordered for you for {event}. + +You can view the details and status of your ticket here: +{url} + Best regards, Your {event} team""")) }, diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index b6ac1fd1e6..79dad0306a 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -1191,6 +1191,24 @@ class MailSettingsForm(SettingsForm): help_text=_("This will only be sent out for non-free orders. Free orders will receive the free order " "template from below instead."), ) + mail_send_order_approved_attendee = forms.BooleanField( + label=_("Send an email to attendees"), + help_text=_('If the order contains attendees with email addresses different from the person who orders the ' + 'tickets, the following email will be sent out to the attendees.'), + required=False, + ) + mail_subject_order_approved_attendee = I18nFormField( + label=_("Subject sent to attendees"), + required=False, + widget=I18nTextInput, + ) + mail_text_order_approved_attendee = I18nFormField( + label=_("Text sent to attendees"), + required=False, + widget=I18nTextarea, + help_text=_("This will only be sent out for non-free orders. Free orders will receive the free order " + "template from below instead."), + ) mail_subject_order_approved_free = I18nFormField( label=_("Subject for approved free order"), required=False, @@ -1203,6 +1221,24 @@ class MailSettingsForm(SettingsForm): help_text=_("This will only be sent out for free orders. Non-free orders will receive the non-free order " "template from above instead."), ) + mail_send_order_approved_free_attendee = forms.BooleanField( + label=_("Send an email to attendees"), + help_text=_('If the order contains attendees with email addresses different from the person who orders the ' + 'tickets, the following email will be sent out to the attendees.'), + required=False, + ) + mail_subject_order_approved_free_attendee = I18nFormField( + label=_("Subject sent to attendees"), + required=False, + widget=I18nTextInput, + ) + mail_text_order_approved_free_attendee = I18nFormField( + label=_("Text sent to attendees"), + required=False, + widget=I18nTextarea, + help_text=_("This will only be sent out for free orders. Non-free orders will receive the non-free order " + "template from above instead."), + ) mail_subject_order_denied = I18nFormField( label=_("Subject for denied order"), required=False, diff --git a/src/pretix/control/templates/pretixcontrol/event/mail.html b/src/pretix/control/templates/pretixcontrol/event/mail.html index aeac8104c2..763e4f8588 100644 --- a/src/pretix/control/templates/pretixcontrol/event/mail.html +++ b/src/pretix/control/templates/pretixcontrol/event/mail.html @@ -118,7 +118,7 @@ {% include "pretixcontrol/event/mail_settings_fragment.html" with pid="ticket_reminder" title=title_download_tickets_reminder items="mail_days_download_reminder,mail_subject_download_reminder,mail_text_download_reminder,mail_send_download_reminder_attendee,mail_subject_download_reminder_attendee,mail_text_download_reminder_attendee,mail_sales_channel_download_reminder" exclude="mail_days_download_reminder,mail_send_download_reminder_attendee,mail_sales_channel_download_reminder" %} {% blocktrans asvar title_require_approval %}Order approval process{% endblocktrans %} - {% include "pretixcontrol/event/mail_settings_fragment.html" with pid="ticket_reminder" title=title_require_approval items="mail_subject_order_placed_require_approval,mail_text_order_placed_require_approval,mail_subject_order_approved,mail_text_order_approved,mail_subject_order_approved_free,mail_text_order_approved_free,mail_subject_order_denied,mail_text_order_denied" %} + {% include "pretixcontrol/event/mail_settings_fragment.html" with pid="ticket_reminder" title=title_require_approval items="mail_subject_order_placed_require_approval,mail_text_order_placed_require_approval,mail_subject_order_approved,mail_text_order_approved,mail_send_order_approved_attendee,mail_subject_order_approved_attendee,mail_text_order_approved_attendee,mail_subject_order_approved_free,mail_text_order_approved_free,mail_send_order_approved_free_attendee,mail_subject_order_approved_free_attendee,mail_text_order_approved_free_attendee,mail_subject_order_denied,mail_text_order_denied" exclude="mail_send_order_approved_attendee,mail_send_order_approved_free_attendee"%}

{% trans "Attachments" %}

{% bootstrap_field form.mail_attachment_new_order layout="control" %} diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index acf030e9e6..0f24d8ce06 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -454,12 +454,42 @@ def test_approve(event): assert o1.invoices.count() == 1 assert len(djmail.outbox) == 1 assert 'awaiting payment' in djmail.outbox[0].subject + assert djmail.outbox[0].to == ['dummy@dummy.test'] + + +@pytest.mark.django_db +def test_approve_send_to_attendees(event): + djmail.outbox = [] + event.settings.invoice_generate = True + event.settings.mail_send_order_approved_attendee = True + o1 = Order.objects.create( + code='FOO', event=event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() - timedelta(days=10), + total=10, require_approval=True, locale='en' + ) + ticket = Item.objects.create(event=event, name='Early-bird ticket', + default_price=Decimal('23.00'), admission=True) + OrderPosition.objects.create( + order=o1, item=ticket, variation=None, price=Decimal("23.00"), + attendee_name_parts={'full_name': "Peter"}, attendee_email='attendee@dummy.test', + positionid=1 + ) + o1.create_transactions() + assert o1.transactions.count() == 0 + approve_order(o1) + o1.refresh_from_db() + assert len(djmail.outbox) == 2 + assert djmail.outbox[0].to == ['dummy@dummy.test'] + assert djmail.outbox[1].to == ['attendee@dummy.test'] + assert 'awaiting payment' in djmail.outbox[0].subject + assert 'awaiting payment' not in djmail.outbox[1].subject @pytest.mark.django_db def test_approve_free(event): djmail.outbox = [] - event.settings.invoice_generate = 'True' + event.settings.invoice_generate = True o1 = Order.objects.create( code='FOO', event=event, email='dummy@dummy.test', status=Order.STATUS_PENDING, @@ -474,6 +504,38 @@ def test_approve_free(event): assert o1.invoices.count() == 0 assert len(djmail.outbox) == 1 assert 'confirmed' in djmail.outbox[0].subject + assert djmail.outbox[0].to == ['dummy@dummy.test'] + + +@pytest.mark.django_db +def test_approve_free_send_to_attendees(event): + djmail.outbox = [] + event.settings.invoice_generate = True + event.settings.mail_send_order_approved_free_attendee = True + o1 = Order.objects.create( + code='FOO', event=event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() - timedelta(days=10), + total=0, require_approval=True + ) + ticket = Item.objects.create(event=event, name='Free ticket', + default_price=Decimal('0.00'), admission=True) + OrderPosition.objects.create( + order=o1, item=ticket, variation=None, price=Decimal("0.00"), + attendee_name_parts={'full_name': "Peter"}, attendee_email='attendee@dummy.test', + positionid=1 + ) + approve_order(o1) + o1.refresh_from_db() + assert o1.expires > now() + assert o1.status == Order.STATUS_PAID + assert not o1.require_approval + assert o1.invoices.count() == 0 + assert len(djmail.outbox) == 2 + assert djmail.outbox[0].to == ['dummy@dummy.test'] + assert djmail.outbox[1].to == ['attendee@dummy.test'] + assert 'confirmed' in djmail.outbox[0].subject + assert 'registration' in djmail.outbox[1].subject @pytest.mark.django_db