forked from CGM_Public/pretix_original
- Add send email directly for order - Add email history (from mass and custom) to each specific order
This commit is contained in:
@@ -614,6 +614,15 @@ class MailSettingsForm(SettingsForm):
|
||||
help_text=_("Available placeholders: {event}, {code}, {url}"),
|
||||
validators=[PlaceholderValidator(['{event}', '{code}', '{url}'])]
|
||||
)
|
||||
mail_text_order_custom_mail = I18nFormField(
|
||||
label=_("Text"),
|
||||
required=False,
|
||||
widget=I18nTextarea,
|
||||
help_text=_("Available placeholders: {expire_date}, {event}, {code}, {date}, {url}, "
|
||||
"{invoice_name}, {invoice_company}"),
|
||||
validators=[PlaceholderValidator(['{expire_date}', '{event}', '{code}', '{date}', '{url}',
|
||||
'{invoice_name}', '{invoice_company}'])]
|
||||
)
|
||||
smtp_use_custom = forms.BooleanField(
|
||||
label=_("Use custom SMTP server"),
|
||||
help_text=_("All mail related to your event will be sent over the smtp server specified by you."),
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.utils.formats import localize
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
|
||||
|
||||
from pretix.base.forms import I18nModelForm
|
||||
from pretix.base.forms import I18nModelForm, PlaceholderValidator
|
||||
from pretix.base.models import Item, ItemAddOn, Order, OrderPosition
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.services.pricing import get_price
|
||||
@@ -215,3 +215,30 @@ class OrderLocaleForm(forms.ModelForm):
|
||||
super().__init__(*args, **kwargs)
|
||||
locale_names = dict(settings.LANGUAGES)
|
||||
self.fields['locale'].choices = [(a, locale_names[a]) for a in self.instance.event.settings.locales]
|
||||
|
||||
|
||||
class OrderMailForm(forms.Form):
|
||||
subject = forms.CharField(
|
||||
label=_("Subject"),
|
||||
required=True
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
order = kwargs.pop('order')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['sendto'] = forms.EmailField(
|
||||
label=_("Recipient"),
|
||||
required=True,
|
||||
initial=order.email
|
||||
)
|
||||
self.fields['sendto'].widget.attrs['readonly'] = 'readonly'
|
||||
self.fields['message'] = forms.CharField(
|
||||
label=_("Message"),
|
||||
required=True,
|
||||
widget=forms.Textarea,
|
||||
initial=order.event.settings.mail_text_order_custom_mail.localize(order.locale),
|
||||
help_text=_("Available placeholders: {expire_date}, {event}, {code}, {date}, {url}, "
|
||||
"{invoice_name}, {invoice_company}"),
|
||||
validators=[PlaceholderValidator(['{expire_date}', '{event}', '{code}', '{date}', '{url}',
|
||||
'{invoice_name}', '{invoice_company}'])]
|
||||
)
|
||||
|
||||
@@ -107,6 +107,7 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.order.payment.changed': _('The payment method has been changed.'),
|
||||
'pretix.event.order.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||
'to expire.'),
|
||||
'pretix.event.order.mail_sent': _('A custom email has been sent.'),
|
||||
'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
|
||||
'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
|
||||
'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
{% blocktrans asvar title_order_canceled %}Order canceled{% endblocktrans %}
|
||||
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="order_canceled" title=title_order_canceled items="mail_text_order_canceled" %}
|
||||
|
||||
{% blocktrans asvar title_order_custom_mail %}Order custom mail{% endblocktrans %}
|
||||
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="custom_mail" title=title_order_custom_mail items="mail_text_order_custom_mail" %}
|
||||
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
class="btn btn-default" target="_blank">
|
||||
{% trans "View order as user" %}
|
||||
</a>
|
||||
<a href="{% url "control:event.order.mail_history" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default">
|
||||
{% trans "View email history" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -93,6 +96,9 @@
|
||||
<a href="{% url "control:event.order.contact" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
<a href="{% url "control:event.order.sendmail" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
|
||||
<span class="fa fa-envelope-o"></span>
|
||||
</a>
|
||||
{% if order.status != "c" %}
|
||||
<form class="form-inline helper-display-inline" method="post"
|
||||
action="{% url "control:event.order.resendlink" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Email history" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Email history" %}</h1>
|
||||
<div class="alert alert-info">
|
||||
{% trans "Includes sent custom and mass emails history only." %}
|
||||
</div>
|
||||
<div>
|
||||
<ul class="list-group">
|
||||
{% for log in logs %}
|
||||
<li class="list-group-item logentry">
|
||||
<p class="meta">
|
||||
<span class="fa fa-clock-o"></span> {{ log.datetime|date:"SHORT_DATETIME_FORMAT" }}
|
||||
{% if log.user %}
|
||||
<br/><span class="fa fa-user"></span> {{ log.user.get_full_name }}
|
||||
{% endif %}
|
||||
{% if log.display %}
|
||||
<br/><span class="fa fa-comment-o"></span> {{ log.display }}
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
<strong>{% trans "Subject:" %}
|
||||
{{ log.parsed_data.subject }}</strong>
|
||||
<pre>{{ log.parsed_data.message }}</pre>
|
||||
</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,37 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Send email" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Send email" %}</h1>
|
||||
{% block inner %}
|
||||
<form class="form-horizontal" method="post" action="">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_field form.sendto layout='horizontal' %}
|
||||
{% bootstrap_field form.subject layout='horizontal' %}
|
||||
{% bootstrap_field form.message layout='horizontal' %}
|
||||
{% if request.method == "POST" %}
|
||||
<fieldset>
|
||||
<legend>{% trans "E-mail preview" %}</legend>
|
||||
<div class="tab-pane mail-preview-group">
|
||||
<pre lang="" class="mail-preview">
|
||||
{% for segment in preview_output %}
|
||||
{% spaceless %}
|
||||
{{ segment|linebreaksbr }}
|
||||
{% endspaceless %}
|
||||
{% endfor %}
|
||||
</pre>
|
||||
</div>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-default btn-save pull-left" name="action" value="preview">
|
||||
{% trans "Preview email" %}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Send" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -138,6 +138,10 @@ urlpatterns = [
|
||||
name='event.order.comment'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/change$', orders.OrderChange.as_view(),
|
||||
name='event.order.change'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/sendmail$', orders.OrderSendMail.as_view(),
|
||||
name='event.order.sendmail'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/mail_history$', orders.OrderEmailHistory.as_view(),
|
||||
name='event.order.mail_history'),
|
||||
url(r'^orders/(?P<code>[0-9A-Z]+)/$', orders.OrderDetail.as_view(), name='event.order'),
|
||||
url(r'^invoice/(?P<invoice>[^/]+)$', orders.InvoiceDownload.as_view(),
|
||||
name='event.invoice.download'),
|
||||
|
||||
@@ -443,6 +443,8 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
|
||||
'mail_text_order_expire_warning': ['event', 'url', 'expire_date', 'invoice_name', 'invoice_company'],
|
||||
'mail_text_waiting_list': ['event', 'url', 'product', 'hours', 'code'],
|
||||
'mail_text_order_canceled': ['code', 'event', 'url'],
|
||||
'mail_text_order_custom_mail': ['expire_date', 'event', 'code', 'date', 'url',
|
||||
'invoice_name', 'invoice_company']
|
||||
}
|
||||
|
||||
@cached_property
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
from datetime import timedelta
|
||||
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Count
|
||||
from django.db.models import Count, Q
|
||||
from django.http import FileResponse, Http404, HttpResponseNotAllowed
|
||||
from django.shortcuts import redirect, render
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import DetailView, ListView, TemplateView, View
|
||||
from django.views.generic import (
|
||||
DetailView, FormView, ListView, TemplateView, View,
|
||||
)
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import (
|
||||
CachedFile, CachedTicket, Invoice, InvoiceAddress, Item, ItemVariation,
|
||||
Order, Quota, generate_position_secret, generate_secret,
|
||||
LogEntry, Order, Quota, generate_position_secret, generate_secret,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.services.export import export
|
||||
@@ -33,7 +38,7 @@ from pretix.base.views.async import AsyncAction
|
||||
from pretix.control.forms.filter import EventOrderFilterForm
|
||||
from pretix.control.forms.orders import (
|
||||
CommentForm, ExporterForm, ExtendForm, OrderContactForm, OrderLocaleForm,
|
||||
OrderPositionAddForm, OrderPositionChangeForm,
|
||||
OrderMailForm, OrderPositionAddForm, OrderPositionChangeForm,
|
||||
)
|
||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||
@@ -604,6 +609,114 @@ class OrderLocaleChange(OrderView):
|
||||
return self.get(*args, **kwargs)
|
||||
|
||||
|
||||
class OrderSendMail(EventPermissionRequiredMixin, FormView):
|
||||
template_name = 'pretixcontrol/order/sendmail.html'
|
||||
permission = 'can_change_orders'
|
||||
form_class = OrderMailForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['order'] = Order.objects.get(
|
||||
event=self.request.event,
|
||||
code=self.kwargs['code'].upper()
|
||||
)
|
||||
return kwargs
|
||||
|
||||
def form_invalid(self, form):
|
||||
messages.error(self.request, _('We could not send the email. See below for details.'))
|
||||
return super().form_invalid(form)
|
||||
|
||||
def form_valid(self, form):
|
||||
tz = pytz.timezone(self.request.event.settings.timezone)
|
||||
order = Order.objects.get(
|
||||
event=self.request.event,
|
||||
code=self.kwargs['code'].upper()
|
||||
)
|
||||
self.preview_output = {}
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
invoice_company = order.invoice_address.company
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
with language(order.locale):
|
||||
email_context = {
|
||||
'event': order.event,
|
||||
'code': order.code,
|
||||
'date': date_format(order.datetime.astimezone(tz), 'SHORT_DATETIME_FORMAT'),
|
||||
'expire_date': date_format(order.expires, 'SHORT_DATE_FORMAT'),
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
|
||||
email_content = form.cleaned_data['message'].format_map(email_context)
|
||||
if self.request.POST.get('action') == 'preview':
|
||||
self.preview_output = []
|
||||
self.preview_output.append(
|
||||
_('Subject: {subject}').format(subject=form.cleaned_data['subject']))
|
||||
self.preview_output.append(email_content)
|
||||
return self.get(self.request, *self.args, **self.kwargs)
|
||||
else:
|
||||
try:
|
||||
with language(order.locale):
|
||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||
mail(
|
||||
order.email, form.cleaned_data['subject'],
|
||||
email_template, email_context,
|
||||
self.request.event, locale=order.locale,
|
||||
order=order
|
||||
)
|
||||
order.log_action(
|
||||
'pretix.event.order.mail_sent',
|
||||
user=self.request.user,
|
||||
data={
|
||||
'subject': form.cleaned_data['subject'],
|
||||
'message': email_content,
|
||||
'recipient': form.cleaned_data['sendto'],
|
||||
}
|
||||
)
|
||||
messages.success(self.request, _('Your message has been queued and will be sent to {}.'.format(order.email)))
|
||||
except SendMailException:
|
||||
messages.error(
|
||||
self.request,
|
||||
_('Failed to send mail to the following user: {}'.format(order.email))
|
||||
)
|
||||
return super(OrderSendMail, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('control:event.order', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'code': self.kwargs['code']}
|
||||
)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
ctx = super().get_context_data(*args, **kwargs)
|
||||
ctx['preview_output'] = getattr(self, 'preview_output', None)
|
||||
return ctx
|
||||
|
||||
|
||||
class OrderEmailHistory(EventPermissionRequiredMixin, ListView):
|
||||
template_name = 'pretixcontrol/order/mail_history.html'
|
||||
permission = 'can_view_orders'
|
||||
model = LogEntry
|
||||
context_object_name = 'logs'
|
||||
paginate_by = 5
|
||||
|
||||
def get_queryset(self):
|
||||
order = Order.objects.filter(
|
||||
event=self.request.event,
|
||||
code=self.kwargs['code'].upper()
|
||||
).first()
|
||||
qs = order.all_logentries()
|
||||
qs = qs.filter(Q(action_type="pretix.plugins.sendmail.order.email.sent") | Q(action_type="pretix.event.order.mail_sent"))
|
||||
return qs
|
||||
|
||||
|
||||
class OverView(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/orders/overview.html'
|
||||
permission = 'can_view_orders'
|
||||
|
||||
Reference in New Issue
Block a user