forked from CGM_Public/pretix_original
Refs #126 -- Show order history
This commit is contained in:
@@ -33,7 +33,6 @@ def cached_file_delete(sender, instance, **kwargs):
|
||||
|
||||
|
||||
class LoggingMixin:
|
||||
logentries = GenericRelation('LogEntry')
|
||||
|
||||
def log_action(self, action, data=None, user=None):
|
||||
"""
|
||||
@@ -59,6 +58,10 @@ class LoggingMixin:
|
||||
|
||||
|
||||
class LoggedModel(models.Model, LoggingMixin):
|
||||
logentries = GenericRelation('LogEntry')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def all_logentries(self):
|
||||
return self.logentries.all().select_related('user')
|
||||
|
||||
@@ -28,3 +28,14 @@ class LogEntry(models.Model):
|
||||
event = models.ForeignKey('Event', null=True, blank=True, on_delete=models.CASCADE)
|
||||
action_type = models.CharField(max_length=255)
|
||||
data = models.TextField(default='{}')
|
||||
|
||||
class Meta:
|
||||
ordering = ('-datetime', )
|
||||
|
||||
def display(self):
|
||||
from ..signals import logentry_display
|
||||
|
||||
for receiver, response in logentry_display.send(self.event, logentry=self):
|
||||
if response:
|
||||
return response
|
||||
return self.action_type
|
||||
|
||||
@@ -87,3 +87,11 @@ as the first argument.
|
||||
order_paid = EventPluginSignal(
|
||||
providing_args=["order"]
|
||||
)
|
||||
|
||||
"""
|
||||
This signal is sent out every time we need to display a LogEntry object and we
|
||||
don't know how to turn it into human-readable text.
|
||||
"""
|
||||
logentry_display = EventPluginSignal(
|
||||
providing_args=["logentry"]
|
||||
)
|
||||
|
||||
@@ -7,5 +7,6 @@ class PretixControlConfig(AppConfig):
|
||||
|
||||
def ready(self):
|
||||
from .views import dashboards # noqa
|
||||
from . import logdisplay # noqa
|
||||
|
||||
default_app_config = 'pretix.control.PretixControlConfig'
|
||||
|
||||
20
src/pretix/control/logdisplay.py
Normal file
20
src/pretix/control/logdisplay.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from pretix.base.signals import logentry_display
|
||||
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="pretixcontrol_logentry_display")
|
||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
||||
plains = {
|
||||
'pretix.event.order.modified': _('The order details have been modified.'),
|
||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||
'pretix.event.order.resend': _('The link to the order detail page has been resent to the user.'),
|
||||
'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
|
||||
'pretix.event.order.paid': _('The order has been marked as paid.'),
|
||||
'pretix.event.order.refunded': _('The order has been refunded.'),
|
||||
'pretix.event.order.cancelled': _('The order has been cancelled.'),
|
||||
'pretix.event.order.placed': _('The order has been created.'),
|
||||
}
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
@@ -0,0 +1,16 @@
|
||||
<ul class="list-group">
|
||||
{% for log in obj.all_logentries %}
|
||||
<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 }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ log.display }}
|
||||
</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -47,186 +47,202 @@
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="panel panel-primary items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Order details" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Order code" %}</dt>
|
||||
<dd>{{ order.code }}</dd>
|
||||
<dt>{% trans "Order date" %}</dt>
|
||||
<dd>{{ order.datetime }}</dd>
|
||||
{% if order.status == "p" %}
|
||||
<dt>{% trans "Payment date" %}</dt>
|
||||
<dd>{{ order.payment_date }}</dd>
|
||||
{% elif order.status == "n" %}
|
||||
<dt>{% trans "Expiry date" %}</dt>
|
||||
<dd>{{ order.expires }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "User" %}</dt>
|
||||
<dd>
|
||||
{{ order.email }}
|
||||
<form class="form-inline" style="display: inline;" method="post"
|
||||
action="{% url "control:event.order.resendlink" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-default btn-xs">
|
||||
{% trans "Resend link" %}
|
||||
</button>
|
||||
</form>
|
||||
</dd>
|
||||
{% if invoices %}
|
||||
<dt>{% trans "Invoices" %}</dt>
|
||||
<dd>
|
||||
{% for i in invoices %}
|
||||
<a href="{% url "control:event.invoice.download" invoice=i.pk event=request.event.slug organizer=request.event.organizer.slug %}">
|
||||
{% if i.is_cancellation %}{% trans "Cancellation" %}{% else %}{% trans "Invoice" %}{% endif %}
|
||||
{{ i.number }}</a> ({{ i.date|date:"SHORT_DATE_FORMAT" }})
|
||||
{% if forloop.revcounter0 > 0 %}
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Ordered items" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% for line in items.positions %}
|
||||
<div class="row-fluid product-row">
|
||||
<div class="col-md-4 col-xs-6">
|
||||
<strong>{{ line.item.name }}</strong>
|
||||
{% if line.variation %}
|
||||
– {{ line.variation }}
|
||||
{% endif %}
|
||||
{% if line.voucher %}
|
||||
<br/><span class="fa fa-ticket"></span> {% trans "Voucher code used:" %}
|
||||
<a href="{% url "control:event.voucher" event=request.event.slug organizer=request.event.organizer.slug voucher=line.voucher.pk %}">
|
||||
{{ line.voucher.code }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if line.has_questions %}
|
||||
<dl>
|
||||
{% if line.item.admission and event.settings.attendee_names_asked %}
|
||||
<dt>{% trans "Attendee name" %}</dt>
|
||||
<dd>{% if line.attendee_name %}{{ line.attendee_name }}{% else %}
|
||||
<em>{% trans "not answered" %}</em>{% endif %}</dd>
|
||||
{% endif %}
|
||||
{% for q in line.questions %}
|
||||
<dt>{{ q.question }}</dt>
|
||||
<dd>{% if q.answer %}{{ q.answer }}{% else %}
|
||||
<em>{% trans "not answered" %}</em>{% endif %}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-2 col-xs-6 count">
|
||||
{{ line.count }}
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 price">
|
||||
{{ event.currency }} {{ line.price|floatformat:2 }}
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 price">
|
||||
<strong>{{ event.currency }} {{ line.total|floatformat:2 }}</strong>
|
||||
{% if line.tax_rate %}
|
||||
<br/>
|
||||
<small>{% blocktrans trimmed with rate=line.tax_rate %}
|
||||
incl. {{ rate }}% taxes
|
||||
{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if items.payment_fee %}
|
||||
<div class="row-fluid product-row">
|
||||
<div class="col-md-4 col-xs-6">
|
||||
<strong>{% trans "Payment method fee" %}</strong>
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
|
||||
<strong>{{ event.currency }} {{ items.payment_fee|floatformat:2 }}</strong>
|
||||
{% if order.payment_fee_tax_rate %}
|
||||
<br/>
|
||||
<small>{% blocktrans trimmed with rate=order.payment_fee_tax_rate %}
|
||||
incl. {{ rate }}% taxes
|
||||
{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row-fluid product-row total">
|
||||
<div class="col-md-4 col-xs-6">
|
||||
<strong>{% trans "Total" %}</strong>
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
|
||||
<strong>{{ event.currency }} {{ items.total|floatformat:2 }}</strong>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="{% if request.event.settings.invoice_address_asked %}col-md-6{% else %}col-md-12{% endif %}">
|
||||
<div class="panel panel-default items">
|
||||
<div class="col-xs-12 col-lg-10">
|
||||
<div class="panel panel-primary items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Payment information" %}
|
||||
{% trans "Order details" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if order.payment_manual %}
|
||||
<div class="alert alert-info">
|
||||
{% trans "The payment state of this order was manually modified." %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Order code" %}</dt>
|
||||
<dd>{{ order.code }}</dd>
|
||||
<dt>{% trans "Order date" %}</dt>
|
||||
<dd>{{ order.datetime }}</dd>
|
||||
{% if order.status == "p" %}
|
||||
<dt>{% trans "Payment date" %}</dt>
|
||||
<dd>{{ order.payment_date }}</dd>
|
||||
{% elif order.status == "n" %}
|
||||
<dt>{% trans "Expiry date" %}</dt>
|
||||
<dd>{{ order.expires }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "User" %}</dt>
|
||||
<dd>
|
||||
{{ order.email }}
|
||||
<form class="form-inline" style="display: inline;" method="post"
|
||||
action="{% url "control:event.order.resendlink" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-default btn-xs">
|
||||
{% trans "Resend link" %}
|
||||
</button>
|
||||
</form>
|
||||
</dd>
|
||||
{% if invoices %}
|
||||
<dt>{% trans "Invoices" %}</dt>
|
||||
<dd>
|
||||
{% for i in invoices %}
|
||||
<a href="{% url "control:event.invoice.download" invoice=i.pk event=request.event.slug organizer=request.event.organizer.slug %}">
|
||||
{% if i.is_cancellation %}{% trans "Cancellation" %}{% else %}{% trans "Invoice" %}{% endif %}
|
||||
{{ i.number }}</a> ({{ i.date|date:"SHORT_DATE_FORMAT" }})
|
||||
{% if forloop.revcounter0 > 0 %}
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Ordered items" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% for line in items.positions %}
|
||||
<div class="row-fluid product-row">
|
||||
<div class="col-md-4 col-xs-6">
|
||||
<strong>{{ line.item.name }}</strong>
|
||||
{% if line.variation %}
|
||||
– {{ line.variation }}
|
||||
{% endif %}
|
||||
{% if line.voucher %}
|
||||
<br/><span class="fa fa-ticket"></span> {% trans "Voucher code used:" %}
|
||||
<a href="{% url "control:event.voucher" event=request.event.slug organizer=request.event.organizer.slug voucher=line.voucher.pk %}">
|
||||
{{ line.voucher.code }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if line.has_questions %}
|
||||
<dl>
|
||||
{% if line.item.admission and event.settings.attendee_names_asked %}
|
||||
<dt>{% trans "Attendee name" %}</dt>
|
||||
<dd>{% if line.attendee_name %}{{ line.attendee_name }}{% else %}
|
||||
<em>{% trans "not answered" %}</em>{% endif %}</dd>
|
||||
{% endif %}
|
||||
{% for q in line.questions %}
|
||||
<dt>{{ q.question }}</dt>
|
||||
<dd>{% if q.answer %}{{ q.answer }}{% else %}
|
||||
<em>{% trans "not answered" %}</em>{% endif %}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-2 col-xs-6 count">
|
||||
{{ line.count }}
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 price">
|
||||
{{ event.currency }} {{ line.price|floatformat:2 }}
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 price">
|
||||
<strong>{{ event.currency }} {{ line.total|floatformat:2 }}</strong>
|
||||
{% if line.tax_rate %}
|
||||
<br/>
|
||||
<small>{% blocktrans trimmed with rate=line.tax_rate %}
|
||||
incl. {{ rate }}% taxes
|
||||
{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if items.payment_fee %}
|
||||
<div class="row-fluid product-row">
|
||||
<div class="col-md-4 col-xs-6">
|
||||
<strong>{% trans "Payment method fee" %}</strong>
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
|
||||
<strong>{{ event.currency }} {{ items.payment_fee|floatformat:2 }}</strong>
|
||||
{% if order.payment_fee_tax_rate %}
|
||||
<br/>
|
||||
<small>{% blocktrans trimmed with rate=order.payment_fee_tax_rate %}
|
||||
incl. {{ rate }}% taxes
|
||||
{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ payment }}
|
||||
{% if order.status == 'n' %}
|
||||
<p>{% blocktrans trimmed with date=order.expires %}
|
||||
The payment has to be completed before {{ date }}.
|
||||
{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
<div class="row-fluid product-row total">
|
||||
<div class="col-md-4 col-xs-6">
|
||||
<strong>{% trans "Total" %}</strong>
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
|
||||
<strong>{{ event.currency }} {{ items.total|floatformat:2 }}</strong>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="{% if request.event.settings.invoice_address_asked %}col-md-6{% else %}col-md-12{% endif %}">
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Payment information" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if order.payment_manual %}
|
||||
<div class="alert alert-info">
|
||||
{% trans "The payment state of this order was manually modified." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ payment }}
|
||||
{% if order.status == 'n' %}
|
||||
<p>{% blocktrans trimmed with date=order.expires %}
|
||||
The payment has to be completed before {{ date }}.
|
||||
{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if request.event.settings.invoice_address_asked %}
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Invoice information" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Company" %}</dt>
|
||||
<dd>{{ order.invoice_address.company }}</dd>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ order.invoice_address.name }}</dd>
|
||||
<dt>{% trans "Address" %}</dt>
|
||||
<dd>{{ order.invoice_address.street|linebreaksbr }}</dd>
|
||||
<dt>{% trans "ZIP code and city" %}</dt>
|
||||
<dd>{{ order.invoice_address.zipcode }} {{ addr.city }}</dd>
|
||||
<dt>{% trans "Country" %}</dt>
|
||||
<dd>{{ order.invoice_address.country }}</dd>
|
||||
<dt>{% trans "Phone" %}</dt>
|
||||
<dd>{{ order.invoice_address.phone }}</dd>
|
||||
{% if request.event.settings.invoice_address_vatid %}
|
||||
<dt>{% trans "VAT ID" %}</dt>
|
||||
<dd>{{ order.invoice_address.vat_id }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if request.event.settings.invoice_address_asked %}
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Invoice information" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Company" %}</dt>
|
||||
<dd>{{ order.invoice_address.company }}</dd>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ order.invoice_address.name }}</dd>
|
||||
<dt>{% trans "Address" %}</dt>
|
||||
<dd>{{ order.invoice_address.street|linebreaksbr }}</dd>
|
||||
<dt>{% trans "ZIP code and city" %}</dt>
|
||||
<dd>{{ order.invoice_address.zipcode }} {{ addr.city }}</dd>
|
||||
<dt>{% trans "Country" %}</dt>
|
||||
<dd>{{ order.invoice_address.country }}</dd>
|
||||
<dt>{% trans "Phone" %}</dt>
|
||||
<dd>{{ order.invoice_address.phone }}</dd>
|
||||
{% if request.event.settings.invoice_address_vatid %}
|
||||
<dt>{% trans "VAT ID" %}</dt>
|
||||
<dd>{{ order.invoice_address.vat_id }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-lg-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Order history" %}
|
||||
</h3>
|
||||
</div>
|
||||
{% include "pretixcontrol/includes/logs.html" with obj=order %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -180,7 +180,7 @@ class OrderTransition(OrderView):
|
||||
self.order.status = Order.STATUS_PENDING
|
||||
self.order.payment_manual = True
|
||||
self.order.save()
|
||||
self.order.log_action('pretix.base.order.unpaid', user=self.request.user)
|
||||
self.order.log_action('pretix.event.order.unpaid', user=self.request.user)
|
||||
messages.success(self.request, _('The order has been marked as not paid.'))
|
||||
elif self.order.status == 'p' and to == 'r':
|
||||
ret = self.payment_provider.order_control_refund_perform(self.request, self.order)
|
||||
@@ -221,7 +221,7 @@ class OrderResendLink(OrderView):
|
||||
self.order.event, locale=self.order.locale
|
||||
)
|
||||
messages.success(self.request, _('The email has been queued to be sent.'))
|
||||
self.order.log_action('pretix.base.order.resend', user=self.request.user)
|
||||
self.order.log_action('pretix.event.order.resend', user=self.request.user)
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ class OrderExtend(OrderView):
|
||||
if self.form.is_valid():
|
||||
if oldvalue > now():
|
||||
messages.success(self.request, _('The payment term has been changed.'))
|
||||
self.order.log_action('pretix.order.changed', user=self.request.user, data={
|
||||
self.order.log_action('pretix.event.order.expirychanged', user=self.request.user, data={
|
||||
'expires': self.order.expires
|
||||
})
|
||||
self.form.save()
|
||||
@@ -315,7 +315,7 @@ class OrderExtend(OrderView):
|
||||
is_available = self.order._is_still_available()
|
||||
if is_available is True:
|
||||
self.form.save()
|
||||
self.order.log_action('pretix.order.changed', user=self.request.user, data={
|
||||
self.order.log_action('pretix.event.order.expirychanged', user=self.request.user, data={
|
||||
'expires': self.order.expires
|
||||
})
|
||||
messages.success(self.request, _('The payment term has been changed.'))
|
||||
|
||||
@@ -16,6 +16,17 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#sumtoggle {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.logentry {
|
||||
.meta {
|
||||
font-size: 12px;
|
||||
margin: 0 0 5px;
|
||||
}
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user