diff --git a/doc/development/api/general.rst b/doc/development/api/general.rst index ea453734f4..9e163959ad 100644 --- a/doc/development/api/general.rst +++ b/doc/development/api/general.rst @@ -26,7 +26,7 @@ Frontend -------- .. automodule:: pretix.presale.signals - :members: html_head, html_footer, footer_link, front_page_top, front_page_bottom, fee_calculation_for_cart, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, sass_preamble, sass_postamble, checkout_flow_steps, order_info, order_meta_from_request + :members: html_head, html_footer, footer_link, front_page_top, front_page_bottom, fee_calculation_for_cart, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, sass_preamble, sass_postamble, checkout_flow_steps, order_info, order_meta_from_request, position_info Request flow """""""""""" diff --git a/src/pretix/base/email.py b/src/pretix/base/email.py index 0b9abee2fa..0cd68c2fa0 100644 --- a/src/pretix/base/email.py +++ b/src/pretix/base/email.py @@ -8,7 +8,7 @@ from django.template.loader import get_template from django.utils.translation import ugettext_lazy as _ from inlinestyler.utils import inline_css -from pretix.base.models import Event, Order +from pretix.base.models import Event, Order, OrderPosition from pretix.base.signals import register_html_mail_renderers from pretix.base.templatetags.rich_text import markdown_compile_email @@ -44,7 +44,8 @@ class BaseHTMLMailRenderer: def __str__(self): return self.identifier - def render(self, plain_body: str, plain_signature: str, subject: str, order: Order=None) -> str: + def render(self, plain_body: str, plain_signature: str, subject: str, order: Order=None, + position: OrderPosition=None) -> str: """ This method should generate the HTML part of the email. @@ -52,6 +53,7 @@ class BaseHTMLMailRenderer: :param plain_signature: The signature with event organizer contact details in plain text. :param subject: The email subject. :param order: The order if this email is connected to one, otherwise ``None``. + :param position: The order position if this email is connected to one, otherwise ``None``. :return: An HTML string """ raise NotImplementedError() @@ -95,7 +97,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer): def template_name(self): raise NotImplementedError() - def render(self, plain_body: str, plain_signature: str, subject: str, order: Order) -> str: + def render(self, plain_body: str, plain_signature: str, subject: str, order: Order, position: OrderPosition) -> str: body_md = markdown_compile_email(plain_body) htmlctx = { 'site': settings.PRETIX_INSTANCE_NAME, @@ -116,6 +118,9 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer): if order: htmlctx['order'] = order + if position: + htmlctx['position'] = position + tpl = get_template(self.template_name) body_html = inline_css(tpl.render(htmlctx)) return body_html diff --git a/src/pretix/base/migrations/0122_orderposition_web_secret.py b/src/pretix/base/migrations/0122_orderposition_web_secret.py new file mode 100644 index 0000000000..c484563109 --- /dev/null +++ b/src/pretix/base/migrations/0122_orderposition_web_secret.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.1 on 2019-05-15 13:23 + +from django.db import migrations, models + +import pretix.base.models.orders + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0121_order_email_known_to_work'), + ] + + operations = [ + migrations.AddField( + model_name='orderposition', + name='web_secret', + field=models.CharField(db_index=True, default=pretix.base.models.orders.generate_secret, max_length=32), + ), + ] diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 3f7b9321aa..b5c12f545b 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -673,7 +673,7 @@ class Order(LockModel, LoggedModel): def send_mail(self, subject: str, template: Union[str, LazyI18nString], context: Dict[str, Any]=None, log_entry_type: str='pretix.event.order.email.sent', user: User=None, headers: dict=None, sender: str=None, invoices: list=None, - auth=None, attach_tickets=False): + auth=None, attach_tickets=False, position: 'OrderPosition'=None): """ Sends an email to the user that placed this order. Basically, this method does two things: @@ -690,6 +690,9 @@ class Order(LockModel, LoggedModel): :param headers: Dictionary with additional mail headers :param sender: Custom email sender. :param attach_tickets: Attach tickets of this order, if they are existing and ready to download + :param position: An order position this refers to. If given, no invoices will be attached, the tickets will + only be attached for this position and child positions, the link will only point to the + position and the attendee email will be used if available. """ from pretix.base.services.mail import SendMailException, mail, render_mail @@ -701,12 +704,16 @@ class Order(LockModel, LoggedModel): with language(self.locale): recipient = self.email + if position and position.attendee_email: + recipient = position.attendee_email + try: email_content = render_mail(template, context) mail( recipient, subject, template, context, - self.event, self.locale, self, headers, sender, - invoices=invoices, attach_tickets=attach_tickets + self.event, self.locale, self, headers=headers, sender=sender, + invoices=invoices, attach_tickets=attach_tickets, + position=position ) except SendMailException: raise @@ -718,6 +725,7 @@ class Order(LockModel, LoggedModel): data={ 'subject': subject, 'message': email_content, + 'position': position.positionid if position else None, 'recipient': recipient, 'invoices': [i.pk for i in invoices] if invoices else [], 'attach_tickets': attach_tickets, @@ -1194,8 +1202,6 @@ class OrderPayment(models.Model): :raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False`` """ from pretix.base.services.invoices import generate_invoice, invoice_qualified - from pretix.base.services.mail import SendMailException - from pretix.multidomain.urlreverse import build_absolute_uri with transaction.atomic(): locked_instance = OrderPayment.objects.select_for_update().get(pk=self.pk) @@ -1259,36 +1265,77 @@ class OrderPayment(models.Model): ) if send_mail: - with language(self.order.locale): - try: - invoice_name = self.order.invoice_address.name - invoice_company = self.order.invoice_address.company - except InvoiceAddress.DoesNotExist: - invoice_name = "" - invoice_company = "" - email_template = self.order.event.settings.mail_text_order_paid - email_context = { - 'event': self.order.event.name, - 'url': build_absolute_uri(self.order.event, 'presale:event.order.open', kwargs={ - 'order': self.order.code, - 'secret': self.order.secret, - 'hash': self.order.email_confirm_hash() - }), - 'downloads': self.order.event.settings.get('ticket_download', as_type=bool), - 'invoice_name': invoice_name, - 'invoice_company': invoice_company, - 'payment_info': mail_text - } - email_subject = _('Payment received for your order: %(code)s') % {'code': self.order.code} - try: - self.order.send_mail( - email_subject, email_template, email_context, - 'pretix.event.order.email.order_paid', user, - invoices=[invoice] if invoice and self.order.event.settings.invoice_email_attachment else [], - attach_tickets=True - ) - except SendMailException: - logger.exception('Order paid email could not be sent') + 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(): + if p.addon_to_id is None and p.attendee_email and p.attendee_email != self.order.email: + self._send_paid_mail_attendee(p, user) + + def _send_paid_mail_attendee(self, position, user): + from pretix.base.services.mail import SendMailException + from pretix.multidomain.urlreverse import build_absolute_uri + + with language(self.order.locale): + name_scheme = PERSON_NAME_SCHEMES[self.order.event.settings.name_scheme] + email_template = self.order.event.settings.mail_text_order_paid_attendee + email_context = { + 'event': self.order.event.name, + 'downloads': self.order.event.settings.get('ticket_download', as_type=bool), + 'url': build_absolute_uri(self.order.event, 'presale:event.order.position', kwargs={ + 'order': self.order.code, + 'secret': position.web_secret, + 'position': position.positionid + }), + 'attendee_name': position.attendee_name, + } + for f, l, w in name_scheme['fields']: + email_context['attendee_name_%s' % f] = position.attendee_name_parts.get(f, '') + + email_subject = _('Event registration confirmed: %(code)s') % {'code': self.order.code} + try: + self.order.send_mail( + email_subject, email_template, email_context, + 'pretix.event.order.email.order_paid', user, + invoices=[], position=position, + attach_tickets=True + ) + except SendMailException: + logger.exception('Order paid email could not be sent') + + def _send_paid_mail(self, invoice, user, mail_text): + from pretix.base.services.mail import SendMailException + from pretix.multidomain.urlreverse import build_absolute_uri + + with language(self.order.locale): + try: + invoice_name = self.order.invoice_address.name + invoice_company = self.order.invoice_address.company + except InvoiceAddress.DoesNotExist: + invoice_name = "" + invoice_company = "" + email_template = self.order.event.settings.mail_text_order_paid + email_context = { + 'event': self.order.event.name, + 'url': build_absolute_uri(self.order.event, 'presale:event.order.open', kwargs={ + 'order': self.order.code, + 'secret': self.order.secret, + 'hash': self.order.email_confirm_hash() + }), + 'downloads': self.order.event.settings.get('ticket_download', as_type=bool), + 'invoice_name': invoice_name, + 'invoice_company': invoice_company, + 'payment_info': mail_text + } + email_subject = _('Payment received for your order: %(code)s') % {'code': self.order.code} + try: + self.order.send_mail( + email_subject, email_template, email_context, + 'pretix.event.order.email.order_paid', user, + invoices=[invoice] if invoice and self.order.event.settings.invoice_email_attachment else [], + attach_tickets=True + ) + except SendMailException: + logger.exception('Order paid email could not be sent') @property def refunded_amount(self): @@ -1677,6 +1724,7 @@ class OrderPosition(AbstractPosition): verbose_name=_('Tax value') ) secret = models.CharField(max_length=64, default=generate_position_secret, db_index=True) + web_secret = models.CharField(max_length=32, default=generate_secret, db_index=True) pseudonymization_id = models.CharField( max_length=16, unique=True, @@ -1800,6 +1848,60 @@ class OrderPosition(AbstractPosition): def event(self): return self.order.event + def send_mail(self, subject: str, template: Union[str, LazyI18nString], + context: Dict[str, Any]=None, log_entry_type: str='pretix.event.order.email.sent', + user: User=None, headers: dict=None, sender: str=None, invoices: list=None, + auth=None, attach_tickets=False): + """ + Sends an email to the user that placed this order. Basically, this method does two things: + + * Call ``pretix.base.services.mail.mail`` with useful values for the ``event``, ``locale``, ``recipient`` and + ``order`` parameters. + + * Create a ``LogEntry`` with the email contents. + + :param subject: Subject of the email + :param template: LazyI18nString or template filename, see ``pretix.base.services.mail.mail`` for more details + :param context: Dictionary to use for rendering the template + :param log_entry_type: Key to be used for the log entry + :param user: Administrative user who triggered this mail to be sent + :param headers: Dictionary with additional mail headers + :param sender: Custom email sender. + :param attach_tickets: Attach tickets of this order, if they are existing and ready to download + """ + from pretix.base.services.mail import SendMailException, mail, render_mail + + if not self.email: + return + + for k, v in self.event.meta_data.items(): + context['meta_' + k] = v + + with language(self.locale): + recipient = self.email + try: + email_content = render_mail(template, context) + mail( + recipient, subject, template, context, + self.event, self.locale, self, headers, sender, + invoices=invoices, attach_tickets=attach_tickets + ) + except SendMailException: + raise + else: + self.log_action( + log_entry_type, + user=user, + auth=auth, + data={ + 'subject': subject, + 'message': email_content, + 'recipient': recipient, + 'invoices': [i.pk for i in invoices] if invoices else [], + 'attach_tickets': attach_tickets, + } + ) + class CartPosition(AbstractPosition): """ diff --git a/src/pretix/base/services/mail.py b/src/pretix/base/services/mail.py index 14023015d3..7e979842fb 100644 --- a/src/pretix/base/services/mail.py +++ b/src/pretix/base/services/mail.py @@ -1,5 +1,6 @@ import logging import smtplib +import warnings from email.utils import formataddr from typing import Any, Dict, List, Union @@ -13,7 +14,9 @@ from i18nfield.strings import LazyI18nString from pretix.base.email import ClassicMailRenderer from pretix.base.i18n import language -from pretix.base.models import Event, Invoice, InvoiceAddress, Order +from pretix.base.models import ( + Event, Invoice, InvoiceAddress, Order, OrderPosition, +) from pretix.base.services.invoices import invoice_pdf_task from pretix.base.services.tasks import TransactionAwareTask from pretix.base.services.tickets import get_tickets_for_order @@ -38,8 +41,8 @@ class SendMailException(Exception): def mail(email: str, subject: str, template: Union[str, LazyI18nString], context: Dict[str, Any]=None, event: Event=None, locale: str=None, - order: Order=None, headers: dict=None, sender: str=None, invoices: list=None, - attach_tickets=False): + order: Order=None, position: OrderPosition=None, headers: dict=None, sender: str=None, + invoices: list=None, attach_tickets=False): """ Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation. @@ -60,6 +63,9 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString], :param order: The order this email is related to (optional). If set, this will be used to include a link to the order below the email. + :param order: The order position this email is related to (optional). If set, this will be used to include a link + to the order position instead of the order below the email. + :param headers: A dict of custom mail headers to add to the mail :param locale: The locale to be used while evaluating the subject and the template @@ -132,9 +138,26 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString], body_plain += signature body_plain += "\r\n\r\n-- \r\n" - if order: - if order.testmode: - subject = "[TESTMODE] " + subject + if order and order.testmode: + subject = "[TESTMODE] " + subject + + if order and position: + body_plain += _( + "You are receiving this email because someone placed an order for {event} for you." + ).format(event=event.name) + body_plain += "\r\n" + body_plain += _( + "You can view your order details at the following URL:\n{orderurl}." + ).replace("\n", "\r\n").format( + event=event.name, orderurl=build_absolute_uri( + order.event, 'presale:event.order.position', kwargs={ + 'order': order.code, + 'secret': position.web_secret, + 'position': position.positionid, + } + ) + ) + elif order: body_plain += _( "You are receiving this email because you placed an order for {event}." ).format(event=event.name) @@ -153,7 +176,14 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString], body_plain += "\r\n" try: - body_html = renderer.render(content_plain, signature, str(subject), order) + try: + body_html = renderer.render(content_plain, signature, str(subject), order, position) + except TypeError: + # Backwards compatibility + warnings.warn('E-mail renderer called without position argument because position argument is not ' + 'supported.', + DeprecationWarning) + body_html = renderer.render(content_plain, signature, str(subject), order) except: logger.exception('Could not render HTML body') body_html = None @@ -167,8 +197,9 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString], sender=sender, event=event.id if event else None, headers=headers, - invoices=[i.pk for i in invoices] if invoices else [], + invoices=[i.pk for i in invoices] if invoices and not position else [], order=order.pk if order else None, + position=position.pk if position else None, attach_tickets=attach_tickets ) @@ -183,8 +214,8 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString], @app.task(base=TransactionAwareTask, bind=True) def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: str, sender: str, - event: int=None, headers: dict=None, bcc: List[str]=None, invoices: List[int]=None, - order: int=None, attach_tickets=False) -> bool: + event: int=None, position: int=None, headers: dict=None, bcc: List[str]=None, + invoices: List[int]=None, order: int=None, attach_tickets=False) -> bool: email = EmailMultiAlternatives(subject, body, sender, to=to, bcc=bcc, headers=headers) if html is not None: email.attach_alternative(html, "text/html") @@ -215,10 +246,15 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st except Order.DoesNotExist: order = None else: + if position: + try: + position = order.positions.get(pk=position) + except OrderPosition.DoesNotExist: + attach_tickets = False if attach_tickets: args = [] attach_size = 0 - for name, ct in get_tickets_for_order(order): + for name, ct in get_tickets_for_order(order, base_position=position): content = ct.file.read() args.append((name, content, ct.type)) attach_size += len(content) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 946265e0dd..811d2773a2 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -43,6 +43,7 @@ from pretix.base.services.locking import LockTimeoutException, NoLockManager from pretix.base.services.mail import SendMailException from pretix.base.services.pricing import get_price from pretix.base.services.tasks import ProfiledTask +from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.signals import ( allow_ticket_download, order_approved, order_canceled, order_changed, order_denied, order_expired, order_fee_calculation, order_placed, @@ -645,6 +646,75 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d return order, p +def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider, email_template, log_entry: str, + invoice): + try: + invoice_name = order.invoice_address.name + invoice_company = order.invoice_address.company + except InvoiceAddress.DoesNotExist: + invoice_name = "" + invoice_company = "" + + if pprov: + payment_info = str(pprov.order_pending_mail_render(order)) + else: + payment_info = None + + email_context = { + 'total': LazyNumber(order.total), + 'currency': event.currency, + 'total_with_currency': LazyCurrencyNumber(order.total, event.currency), + 'date': LazyDate(order.expires), + 'event': event.name, + 'url': build_absolute_uri(event, 'presale:event.order.open', kwargs={ + 'order': order.code, + 'secret': order.secret, + 'hash': order.email_confirm_hash() + }), + 'payment_info': payment_info, + 'invoice_name': invoice_name, + 'invoice_company': invoice_company, + } + email_subject = _('Your order: %(code)s') % {'code': order.code} + try: + order.send_mail( + email_subject, email_template, email_context, + log_entry, + invoices=[invoice] if invoice and event.settings.invoice_email_attachment else [], + attach_tickets=True + ) + except SendMailException: + logger.exception('Order received email could not be sent') + + +def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosition, email_template, log_entry: str): + name_scheme = PERSON_NAME_SCHEMES[event.settings.name_scheme] + email_context = { + 'event': event.name, + 'url': build_absolute_uri(event, 'presale:event.order.position', kwargs={ + 'order': order.code, + 'secret': position.web_secret, + 'position': position.positionid + }), + 'attendee_name': position.attendee_name, + } + for f, l, w in name_scheme['fields']: + email_context['attendee_name_%s' % f] = position.attendee_name_parts.get(f, '') + + email_subject = _('Your event registration: %(code)s') % {'code': order.code} + + try: + order.send_mail( + email_subject, email_template, email_context, + log_entry, + invoices=[], + attach_tickets=True, + position=position + ) + except SendMailException: + logger.exception('Order received email could not be sent to attendee') + + def _perform_order(event: str, payment_provider: str, position_ids: List[str], email: str, locale: str, address: int, meta_info: dict=None, sales_channel: str='web'): @@ -709,50 +779,26 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str], if order.require_approval: email_template = event.settings.mail_text_order_placed_require_approval log_entry = 'pretix.event.order.email.order_placed_require_approval' + + email_attendees = False elif free_order_flow: email_template = event.settings.mail_text_order_free log_entry = 'pretix.event.order.email.order_free' + + email_attendees = event.settings.mail_send_order_free_attendee + email_attendees_template = event.settings.mail_text_order_free_attendee else: email_template = event.settings.mail_text_order_placed log_entry = 'pretix.event.order.email.order_placed' - try: - invoice_name = order.invoice_address.name - invoice_company = order.invoice_address.company - except InvoiceAddress.DoesNotExist: - invoice_name = "" - invoice_company = "" + email_attendees = event.settings.mail_send_order_placed_attendee + email_attendees_template = event.settings.mail_text_order_placed_attendee - if pprov: - payment_info = str(pprov.order_pending_mail_render(order)) - else: - payment_info = None - - email_context = { - 'total': LazyNumber(order.total), - 'currency': event.currency, - 'total_with_currency': LazyCurrencyNumber(order.total, event.currency), - 'date': LazyDate(order.expires), - 'event': event.name, - 'url': build_absolute_uri(event, 'presale:event.order.open', kwargs={ - 'order': order.code, - 'secret': order.secret, - 'hash': order.email_confirm_hash() - }), - 'payment_info': payment_info, - 'invoice_name': invoice_name, - 'invoice_company': invoice_company, - } - email_subject = _('Your order: %(code)s') % {'code': order.code} - try: - order.send_mail( - email_subject, email_template, email_context, - log_entry, - invoices=[invoice] if invoice and event.settings.invoice_email_attachment else [], - attach_tickets=True - ) - except SendMailException: - logger.exception('Order received email could not be sent') + _order_placed_email(event, order, pprov, email_template, log_entry, invoice) + 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 @@ -873,6 +919,31 @@ def send_download_reminders(sender, **kwargs): except SendMailException: logger.exception('Reminder email could not be sent') + if e.settings.mail_send_download_reminder_attendee: + name_scheme = PERSON_NAME_SCHEMES[e.settings.name_scheme] + for p in o.positions.all(): + if p.addon_to_id is None and p.attendee_email and p.attendee_email != o.email: + email_template = e.settings.mail_text_download_reminder_attendee + email_context = { + 'event': e.name, + 'url': build_absolute_uri(e, 'presale:event.order.position', kwargs={ + 'order': o.code, + 'secret': p.web_secret, + 'position': p.positionid + }), + 'attendee_name': p.attendee_name, + } + for f, l, w in name_scheme['fields']: + email_context['attendee_name_%s' % f] = p.attendee_name_parts.get(f, '') + try: + o.send_mail( + email_subject, email_template, email_context, + 'pretix.event.order.email.download_reminder_sent', + attach_tickets=True, position=p + ) + except SendMailException: + logger.exception('Reminder email could not be sent to attendee') + class OrderChangeManager: error_messages = { diff --git a/src/pretix/base/services/tickets.py b/src/pretix/base/services/tickets.py index c418816750..2b006e89c3 100644 --- a/src/pretix/base/services/tickets.py +++ b/src/pretix/base/services/tickets.py @@ -96,7 +96,7 @@ def preview(event: int, provider: str): return prov.generate(p) -def get_tickets_for_order(order): +def get_tickets_for_order(order, base_position=None): can_download = all([r for rr, r in allow_ticket_download.send(order.event, order=order)]) if not can_download: return [] @@ -111,13 +111,20 @@ def get_tickets_for_order(order): tickets = [] + positions = list(order.positions_with_tickets) + if base_position: + # Only the given position and its children + positions = [ + p for p in positions if p.pk == base_position.pk or p.addon_to_id == base_position.pk + ] + for p in providers: if not p.is_enabled: continue - if p.multi_download_enabled: + if p.multi_download_enabled and not base_position: try: - if len(list(order.positions_with_tickets)) == 0: + if len(positions) == 0: continue ct = CachedCombinedTicket.objects.filter( order=order, provider=p.identifier, file__isnull=False @@ -136,7 +143,7 @@ def get_tickets_for_order(order): except: logger.exception('Failed to generate ticket.') else: - for pos in order.positions_with_tickets: + for pos in positions: try: ct = CachedTicket.objects.filter( order_position=pos, provider=p.identifier, file__isnull=False diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 952970965e..37c2bae4cd 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -331,6 +331,18 @@ The list is as follows: {orders} +Best regards, +Your {event} team""")) + }, + 'mail_text_order_free_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(ugettext_noop("""Hello {attendee_name}, + +you have been registered for {event} successfully. + +You can view the details and status of your ticket here: +{url} + Best regards, Your {event} team""")) }, @@ -347,6 +359,10 @@ You can change your order details and view the status of your order at Best regards, Your {event} team""")) }, + 'mail_send_order_free_attendee': { + 'type': bool, + 'default': 'False' + }, 'mail_text_order_placed_require_approval': { 'type': LazyI18nString, 'default': LazyI18nString.from_gettext(ugettext_noop("""Hello, @@ -373,6 +389,22 @@ of {total_with_currency}. Please complete your payment before {date}. You can change your order details and view the status of your order at {url} +Best regards, +Your {event} team""")) + }, + 'mail_send_order_placed_attendee': { + 'type': bool, + 'default': 'False' + }, + 'mail_text_order_placed_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(ugettext_noop("""Hello {attendee_name}, + +a ticket for {event} has been ordered for you. + +You can view the details and status of your ticket here: +{url} + Best regards, Your {event} team""")) }, @@ -399,6 +431,22 @@ we successfully received your payment for {event}. Thank you! You can change your order details and view the status of your order at {url} +Best regards, +Your {event} team""")) + }, + 'mail_send_order_paid_attendee': { + 'type': bool, + 'default': 'False' + }, + 'mail_text_order_paid_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(ugettext_noop("""Hello {attendee_name}, + +a ticket for {event} that has been ordered for you is now paid. + +You can view the details and status of your ticket here: +{url} + Best regards, Your {event} team""")) }, @@ -500,6 +548,22 @@ Your {event} team""")) 'type': int, 'default': None }, + 'mail_send_download_reminder_attendee': { + 'type': bool, + 'default': 'False' + }, + 'mail_text_download_reminder_attendee': { + 'type': LazyI18nString, + 'default': LazyI18nString.from_gettext(ugettext_noop("""Hello {attendee_name}, + +you are registered for {event}. + +If you did not do so already, you can download your ticket here: +{url} + +Best regards, +Your {event} team""")) + }, 'mail_text_download_reminder': { 'type': LazyI18nString, 'default': LazyI18nString.from_gettext(ugettext_noop("""Hello, diff --git a/src/pretix/base/templates/pretixbase/email/plainwrapper.html b/src/pretix/base/templates/pretixbase/email/plainwrapper.html index f1ff19a682..95a6333644 100644 --- a/src/pretix/base/templates/pretixbase/email/plainwrapper.html +++ b/src/pretix/base/templates/pretixbase/email/plainwrapper.html @@ -23,13 +23,23 @@
- {% trans "You are receiving this email because you placed an order for the following event:" %}
- {% trans "Event:" %} {{ event.name }}
- {% trans "Order code:" %} {{ order.code }}
- {% trans "Order date:" %} {{ order.datetime|date:"SHORT_DATE_FORMAT" }}
- - {% trans "View order details" %} - + {% if position %} + {% trans "You are receiving this email because someone signed you up for the following event:" %}
+ {% trans "Event:" %} {{ event.name }}
+ {% trans "Order code:" %} {{ order.code }}
+ {% trans "Order date:" %} {{ order.datetime|date:"SHORT_DATE_FORMAT" }}
+ + {% trans "View registration details" %} + + {% else %} + {% trans "You are receiving this email because you placed an order for the following event:" %}
+ {% trans "Event:" %} {{ event.name }}
+ {% trans "Order code:" %} {{ order.code }}
+ {% trans "Order date:" %} {{ order.datetime|date:"SHORT_DATE_FORMAT" }}
+ + {% trans "View order details" %} + + {% endif %}