diff --git a/doc/development/api/payment.rst b/doc/development/api/payment.rst index a2a1e6050..92d5614b9 100644 --- a/doc/development/api/payment.rst +++ b/doc/development/api/payment.rst @@ -77,6 +77,8 @@ The provider class .. automethod:: checkout_perform + .. automethod:: order_pending_mail_render + .. automethod:: order_pending_render This is an abstract method, you **must** override this! diff --git a/src/pretix/base/mail.py b/src/pretix/base/mail.py new file mode 100644 index 000000000..11ce702fa --- /dev/null +++ b/src/pretix/base/mail.py @@ -0,0 +1,51 @@ +import logging +from django.conf import settings +from django.core.mail import EmailMessage +from django.template.loader import get_template +from django.utils import translation + +from pretix.base.models import User, Event + +logger = logging.getLogger('pretix.base.mail') + + +def mail(user: User, subject: str, template: str, context: dict, event: Event=None): + """ + Sends out an email to a user. + + :param user: The user this should be sent to. + :param subject: The e-mail subject. Should be localized. + :param template: The filename of a template to be used. It will + be rendered with the recipient's locale. + :param context: The context for rendering the template. + :param event: The event, used for determining the sender of the e-mail + + :return: ``False`` on obvious failures, like the user having to e-mail + address, ``True`` otherwise. ``True`` does not necessarily mean that + the email has been sent, just that it has been queued by the e-mail + backend. + """ + if not user.email: + return False + + _lng = translation.get_language() + translation.activate(user.locale or settings.LANGUAGE_CODE) + + tpl = get_template(template) + body = tpl.render(context) + + sender = event.settings.get('mail_from') if event else settings.MAIL_FROM + + email = EmailMessage( + subject, body, sender, + to=[user.email] + ) + + try: + email.send(fail_silently=False) + return True + except Exception: + logger.exception('Error sending e-mail') + return False + finally: + translation.activate(_lng) diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index 40d1495e9..ce40f2bc6 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -248,6 +248,16 @@ class BasePaymentProvider: """ return None + def order_pending_mail_render(self, order: Order) -> str: + """ + After the user submitted his order, he or she will receive a confirmation + e-mail. You can return a string from this method if you want to add additional + information to this e-mail. + + :param order: The order object + """ + return "" + def order_pending_render(self, request: HttpRequest, order: Order) -> str: """ If the user visits a detail page of an order which has not yet been paid but diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 1d4eed3e0..ea98d7ed7 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -4,6 +4,7 @@ import decimal import dateutil.parser from django.db.models import Model +from django.conf import settings from versions.models import Versionable @@ -14,6 +15,7 @@ DEFAULTS = { 'attendee_names_required': 'False', 'reservation_time': '30', 'last_order_modification_date': None, + 'mail_from': settings.MAIL_FROM, } diff --git a/src/pretix/plugins/banktransfer/payment.py b/src/pretix/plugins/banktransfer/payment.py index 0b724b61f..260039b4e 100644 --- a/src/pretix/plugins/banktransfer/payment.py +++ b/src/pretix/plugins/banktransfer/payment.py @@ -41,6 +41,11 @@ class BankTransfer(BasePaymentProvider): ctx = {'request': request, 'form': form, 'settings': self.settings} return template.render(ctx) + def order_pending_mail_render(self, order) -> str: + template = get_template('pretixplugins/banktransfer/email/order_pending.txt') + ctx = {'event': self.event, 'order': order, 'settings': self.settings} + return template.render(ctx) + def order_pending_render(self, request, order) -> str: template = get_template('pretixplugins/banktransfer/pending.html') ctx = {'request': request, 'order': order, 'settings': self.settings} diff --git a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/email/order_pending.txt b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/email/order_pending.txt new file mode 100644 index 000000000..38738c546 --- /dev/null +++ b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/email/order_pending.txt @@ -0,0 +1,5 @@ +{% load i18n %}{% blocktrans with bank=settings.bank_details code=order.full_code %} +Please transfer the full amount to the following bank account. + +Reference: {{ code }} +{{ bank }}{% endblocktrans %} \ No newline at end of file diff --git a/src/pretix/presale/templates/pretixpresale/email/order_placed.txt b/src/pretix/presale/templates/pretixpresale/email/order_placed.txt new file mode 100644 index 000000000..8cc5f371c --- /dev/null +++ b/src/pretix/presale/templates/pretixpresale/email/order_placed.txt @@ -0,0 +1,13 @@ +{% load i18n %}{% blocktrans with event=event.name total=order.total|floatformat:2 currency=event.currency paymentinfo=payment date=order.expires|date url=url %}Hello, + +we successfully received your order for {{ event }} with a total value +of {{ total }} {{ currency }}. Please complete your payment before {{ date }}. +{{ paymentinfo }} + +You can view the status of your order at + +{{ url }} + +Best regards, +Your {{ event }} team +{% endblocktrans %} \ No newline at end of file diff --git a/src/pretix/presale/views/checkout.py b/src/pretix/presale/views/checkout.py index 3cdadac2e..830d76996 100644 --- a/src/pretix/presale/views/checkout.py +++ b/src/pretix/presale/views/checkout.py @@ -4,11 +4,13 @@ from django.core.urlresolvers import reverse from django.db import transaction from django.db.models import Q, Sum from django import forms +from django.http import HttpRequest from django.shortcuts import redirect from django.utils.functional import cached_property from django.utils.timezone import now from django.views.generic import TemplateView from django.utils.translation import ugettext_lazy as _ +from pretix.base.mail import mail from pretix.base.models import CartPosition, Question, QuestionAnswer, Quota, Order, OrderPosition from pretix.base.signals import register_payment_providers @@ -319,7 +321,7 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch self.request = request return self.check_process(request) or self.perform_order(request) - def perform_order(self, request): + def perform_order(self, request: HttpRequest): dt = now() quotas_locked = set() @@ -362,6 +364,17 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch if not self.msg_some_unavailable: # Everything went well order = self._place_order(cartpos, dt) messages.success(request, _('Your order has been placed.')) + mail( + request.user, _('Your order: %(code)s') % {'code': order.code}, + 'pretixpresale/email/order_placed.txt', + { + 'user': request.user, 'order': order, + 'event': request.event, + 'url': request.build_absolute_uri(self.get_order_url(order)), + 'payment': self.payment_provider.order_pending_mail_render(order) + }, + request.event + ) resp = self.payment_provider.checkout_perform(request, order) return redirect(resp or self.get_order_url(order)) diff --git a/src/pretix/settings.py b/src/pretix/settings.py index 2bd52da61..942d4da9d 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -193,7 +193,9 @@ LOGGING = { }, } +MAIL_FROM = 'pretix@localhost' + try: - from local_settings import * # NOQA + from .local_settings import * # NOQA except ImportError: pass