forked from CGM_Public/pretix_original
Refs #126 -- Display logs of vouchers, items, quotas and categories
This commit is contained in:
@@ -472,6 +472,10 @@ class OrderPosition(AbstractPosition):
|
||||
answ.save()
|
||||
if cartpos.voucher:
|
||||
Voucher.objects.filter(pk=cartpos.voucher.pk).update(redeemed=F('redeemed') + 1)
|
||||
cartpos.voucher.log_action('pretix.voucher.redeemed', {
|
||||
'order_code': order.code
|
||||
})
|
||||
|
||||
cartpos.delete()
|
||||
return ops
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.dispatch import receiver
|
||||
from django.utils import formats
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from pretix.base.i18n import LazyI18nString
|
||||
from pretix.base.models import Event, ItemVariation, LogEntry
|
||||
from pretix.base.signals import logentry_display
|
||||
|
||||
@@ -61,44 +62,65 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.order.refunded': _('The order has been refunded.'),
|
||||
'pretix.event.order.canceled': _('The order has been canceled.'),
|
||||
'pretix.event.order.placed': _('The order has been created.'),
|
||||
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
||||
'to "{new_email}".'),
|
||||
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
|
||||
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
|
||||
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
|
||||
'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
|
||||
'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.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||
'to expire.'),
|
||||
'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.'),
|
||||
'pretix.user.settings.2fa.device.added': _('A new two-factor authentication device "{name}" has been added to '
|
||||
'your account.'),
|
||||
'pretix.user.settings.2fa.device.deleted': _('The two-factor authentication device "{name}" has been removed '
|
||||
'from your account.'),
|
||||
'pretix.control.auth.user.forgot_password.mail_sent': _('Password reset mail sent.'),
|
||||
'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.')
|
||||
|
||||
'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.'),
|
||||
'pretix.voucher.added': _('The voucher has been created.'),
|
||||
'pretix.voucher.changed': _('The voucher has been modified.'),
|
||||
'pretix.voucher.deleted': _('The voucher has been deleted.'),
|
||||
'pretix.voucher.redeemed': _('The voucher has been redeemed in order {order_code}.'),
|
||||
'pretix.event.item.added': _('The product has been created.'),
|
||||
'pretix.event.item.changed': _('The product has been modified.'),
|
||||
'pretix.event.item.deleted': _('The product has been deleted.'),
|
||||
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
|
||||
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
|
||||
'pretix.event.item.variation.changed': _('The variation "{value}" has been modified.'),
|
||||
'pretix.event.quota.added': _('The quota has been added.'),
|
||||
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
||||
'pretix.event.quota.changed': _('The quota has been modified.'),
|
||||
'pretix.event.category.added': _('The category has been added.'),
|
||||
'pretix.event.category.deleted': _('The category has been deleted.'),
|
||||
'pretix.event.category.changed': _('The category has been modified.'),
|
||||
'pretix.event.question.added': _('The question has been added.'),
|
||||
'pretix.event.question.deleted': _('The question has been deleted.'),
|
||||
'pretix.event.question.changed': _('The question has been modified.'),
|
||||
}
|
||||
|
||||
data = json.loads(logentry.data)
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.item.variation'):
|
||||
if 'value' not in data:
|
||||
# Backwards compatibility
|
||||
var = ItemVariation.objects.filter(id=data['id']).first()
|
||||
if var:
|
||||
data['value'] = str(var.value)
|
||||
else:
|
||||
data['value'] = '?'
|
||||
else:
|
||||
data['value'] = LazyI18nString(data['value'])
|
||||
|
||||
if logentry.action_type in plains:
|
||||
return plains[logentry.action_type]
|
||||
return plains[logentry.action_type].format_map(data)
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.order.changed'):
|
||||
return _display_order_changed(sender, logentry)
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.order.contact.changed'):
|
||||
data = json.loads(logentry.data)
|
||||
return _('The email address has been changed from "{old}" to "{new}".').format(
|
||||
old=data['old_email'],
|
||||
new=data['new_email'],
|
||||
)
|
||||
|
||||
if logentry.action_type == 'pretix.user.settings.2fa.device.added':
|
||||
data = json.loads(logentry.data)
|
||||
return _('A new two-factor authentication device "{name}" has been added to your account.').format(
|
||||
name=data['name']
|
||||
)
|
||||
if logentry.action_type == 'pretix.user.settings.2fa.device.deleted':
|
||||
data = json.loads(logentry.data)
|
||||
return _('The two-factor authentication device "{name}" has been removed from your account.').format(
|
||||
name=data['name']
|
||||
)
|
||||
if logentry.action_type == 'pretix.user.settings.changed':
|
||||
data = json.loads(logentry.data)
|
||||
text = str(_('Your account settings have been changed.'))
|
||||
if 'email' in data:
|
||||
text = text + ' ' + str(_('Your email address has been changed to {email}.').format(email=data['email']))
|
||||
|
||||
@@ -4,29 +4,43 @@
|
||||
{% block inside %}
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.active layout="horizontal" %}
|
||||
{% bootstrap_field form.category layout="horizontal" %}
|
||||
{% bootstrap_field form.admission layout="horizontal" %}
|
||||
{% bootstrap_field form.description layout="horizontal" %}
|
||||
{% bootstrap_field form.picture layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Price settings" %}</legend>
|
||||
{% bootstrap_field form.default_price layout="horizontal" %}
|
||||
{% bootstrap_field form.tax_rate layout="horizontal" %}
|
||||
{% bootstrap_field form.free_price layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Availability" %}</legend>
|
||||
{% bootstrap_field form.available_from layout="horizontal" %}
|
||||
{% bootstrap_field form.available_until layout="horizontal" %}
|
||||
{% bootstrap_field form.require_voucher layout="horizontal" %}
|
||||
{% bootstrap_field form.hide_without_voucher layout="horizontal" %}
|
||||
{% bootstrap_field form.allow_cancel layout="horizontal" %}
|
||||
</fieldset>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-lg-10">
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.active layout="horizontal" %}
|
||||
{% bootstrap_field form.category layout="horizontal" %}
|
||||
{% bootstrap_field form.admission layout="horizontal" %}
|
||||
{% bootstrap_field form.description layout="horizontal" %}
|
||||
{% bootstrap_field form.picture layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Price settings" %}</legend>
|
||||
{% bootstrap_field form.default_price layout="horizontal" %}
|
||||
{% bootstrap_field form.tax_rate layout="horizontal" %}
|
||||
{% bootstrap_field form.free_price layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Availability" %}</legend>
|
||||
{% bootstrap_field form.available_from layout="horizontal" %}
|
||||
{% bootstrap_field form.available_until layout="horizontal" %}
|
||||
{% bootstrap_field form.require_voucher layout="horizontal" %}
|
||||
{% bootstrap_field form.hide_without_voucher layout="horizontal" %}
|
||||
{% bootstrap_field form.allow_cancel layout="horizontal" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="col-xs-12 col-lg-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Product history" %}
|
||||
</h3>
|
||||
</div>
|
||||
{% include "pretixcontrol/includes/logs.html" with obj=item %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -7,11 +7,25 @@
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form_errors form %}
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.description layout="horizontal" %}
|
||||
</fieldset>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-lg-10">
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.description layout="horizontal" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="col-xs-12 col-lg-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Category history" %}
|
||||
</h3>
|
||||
</div>
|
||||
{% include "pretixcontrol/includes/logs.html" with obj=category %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -36,31 +36,31 @@
|
||||
<button class="btn btn-primary" type="submit">{% trans "Filter" %}</button>
|
||||
</p>
|
||||
</form>
|
||||
{% if not stats %}
|
||||
<div class="empty-collection">
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
No matching answers found.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% if not items %}
|
||||
<div class="row" id="question-stats">
|
||||
{% if not stats %}
|
||||
<div class="empty-collection col-md-10 col-xs-12">
|
||||
<p>
|
||||
{% trans "You need to assign the question to a product to collect answers." %}
|
||||
{% blocktrans trimmed %}
|
||||
No matching answers found.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% if not items %}
|
||||
<p>
|
||||
{% trans "You need to assign the question to a product to collect answers." %}
|
||||
</p>
|
||||
|
||||
<a href="{% url "control:event.items.questions.edit" event=request.event.slug organizer=request.event.organizer.slug question=question.pk %}"
|
||||
class="btn btn-primary btn-lg"><i class="fa fa-edit"></i> {% trans "Edit question" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="row" id="question-stats">
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<a href="{% url "control:event.items.questions.edit" event=request.event.slug organizer=request.event.organizer.slug question=question.pk %}"
|
||||
class="btn btn-primary btn-lg"><i class="fa fa-edit"></i> {% trans "Edit question" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<div class="chart" id="question_chart" data-type="{{ question.type }}">
|
||||
|
||||
</div>
|
||||
<script type="application/json" id="question-chart-data">{{ stats_json|safe }}</script>
|
||||
</div>
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -80,6 +80,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-xs-12 col-lg-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Question history" %}
|
||||
</h3>
|
||||
</div>
|
||||
{% include "pretixcontrol/includes/logs.html" with obj=question %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
{% endif %}
|
||||
</h1>
|
||||
<div class="row" id="quota-stats">
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<legend>{% trans "Usage overview" %}</legend>
|
||||
<div class="chart" id="quota_chart">
|
||||
|
||||
</div>
|
||||
<script type="application/json" id="quota-chart-data">{{ quota_chart_data|safe }}</script>
|
||||
</div>
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<legend>{% trans "Availability calculation" %}</legend>
|
||||
|
||||
<div class="row">
|
||||
@@ -59,6 +59,16 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-2 col-xs-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Quota history" %}
|
||||
</h3>
|
||||
</div>
|
||||
{% include "pretixcontrol/includes/logs.html" with obj=quota %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% eventsignal request.event "pretix.control.signals.quota_detail_html" quota=quota %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -20,40 +20,54 @@
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form_errors form %}
|
||||
<fieldset>
|
||||
<legend>{% trans "Voucher details" %}</legend>
|
||||
{% bootstrap_field form.code layout="horizontal" %}
|
||||
{% bootstrap_field form.max_usages layout="horizontal" %}
|
||||
{% bootstrap_field form.valid_until layout="horizontal" %}
|
||||
{% bootstrap_field form.block_quota layout="horizontal" %}
|
||||
{% bootstrap_field form.allow_ignore_quota layout="horizontal" %}
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label" for="id_tag">{% trans "Price effect" %}</label>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field form.price_mode show_label=False form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{% bootstrap_field form.value show_label=False form_group_class="" %}
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.itemvar layout="horizontal" %}
|
||||
<div class="form-group">
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
<div class="controls">
|
||||
<div class="alert alert-info">
|
||||
{% blocktrans trimmed %}
|
||||
If you choose "any product" for a specific quota and choose to reserve quota for this
|
||||
voucher above, the product can still be unavailable to the voucher holder if another quota
|
||||
associated with the product is sold out!
|
||||
{% endblocktrans %}
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-lg-10">
|
||||
<fieldset>
|
||||
<legend>{% trans "Voucher details" %}</legend>
|
||||
{% bootstrap_field form.code layout="horizontal" %}
|
||||
{% bootstrap_field form.max_usages layout="horizontal" %}
|
||||
{% bootstrap_field form.valid_until layout="horizontal" %}
|
||||
{% bootstrap_field form.block_quota layout="horizontal" %}
|
||||
{% bootstrap_field form.allow_ignore_quota layout="horizontal" %}
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label" for="id_tag">{% trans "Price effect" %}</label>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field form.price_mode show_label=False form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{% bootstrap_field form.value show_label=False form_group_class="" %}
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.itemvar layout="horizontal" %}
|
||||
<div class="form-group">
|
||||
<div class="col-md-9 col-md-offset-3">
|
||||
<div class="controls">
|
||||
<div class="alert alert-info">
|
||||
{% blocktrans trimmed %}
|
||||
If you choose "any product" for a specific quota and choose to reserve quota for this
|
||||
voucher above, the product can still be unavailable to the voucher holder if another quota
|
||||
associated with the product is sold out!
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.tag layout="horizontal" %}
|
||||
{% bootstrap_field form.comment layout="horizontal" %}
|
||||
</fieldset>
|
||||
{% eventsignal request.event "pretix.control.signals.voucher_form_html" form=form %}
|
||||
</div>
|
||||
<div class="col-xs-12 col-lg-2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Voucher history" %}
|
||||
</h3>
|
||||
</div>
|
||||
{% include "pretixcontrol/includes/logs.html" with obj=voucher %}
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.tag layout="horizontal" %}
|
||||
{% bootstrap_field form.comment layout="horizontal" %}
|
||||
</fieldset>
|
||||
{% eventsignal request.event "pretix.control.signals.voucher_form_html" form=form %}
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -831,6 +831,7 @@ class ItemVariations(ItemDetailMixin, EventPermissionRequiredMixin, TemplateView
|
||||
continue
|
||||
self.get_object().log_action(
|
||||
'pretix.event.item.variation.deleted', user=self.request.user, data={
|
||||
'value': form.instance.value,
|
||||
'id': form.instance.pk
|
||||
}
|
||||
)
|
||||
@@ -848,6 +849,7 @@ class ItemVariations(ItemDetailMixin, EventPermissionRequiredMixin, TemplateView
|
||||
form.save()
|
||||
if form.has_changed():
|
||||
change_data = {k: form.cleaned_data.get(k) for k in form.changed_data}
|
||||
change_data['value'] = form.instance.value
|
||||
change_data['id'] = form.instance.pk
|
||||
self.get_object().log_action(
|
||||
'pretix.event.item.variation.changed' if not created else
|
||||
|
||||
Reference in New Issue
Block a user