mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Reorganize UI for exporters (#3025)
Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
@@ -36,7 +36,7 @@ import io
|
||||
import tempfile
|
||||
from collections import OrderedDict, namedtuple
|
||||
from decimal import Decimal
|
||||
from typing import Tuple
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import pytz
|
||||
from defusedcsv import csv
|
||||
@@ -84,6 +84,27 @@ class BaseExporter:
|
||||
"""
|
||||
raise NotImplementedError() # NOQA
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
"""
|
||||
A description for this exporter.
|
||||
"""
|
||||
return ""
|
||||
|
||||
@property
|
||||
def category(self) -> Optional[str]:
|
||||
"""
|
||||
A category name for this exporter, or ``None``.
|
||||
"""
|
||||
return None
|
||||
|
||||
@property
|
||||
def featured(self) -> bool:
|
||||
"""
|
||||
If ``True``, this exporter will be highlighted.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def identifier(self) -> str:
|
||||
"""
|
||||
|
||||
@@ -39,7 +39,7 @@ from zipfile import ZipFile
|
||||
|
||||
from django import forms
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from pretix.base.models import QuestionAnswer
|
||||
|
||||
@@ -49,7 +49,10 @@ from ..signals import register_data_exporters
|
||||
|
||||
class AnswerFilesExporter(BaseExporter):
|
||||
identifier = 'answerfiles'
|
||||
verbose_name = _('Answers to file upload questions')
|
||||
verbose_name = _('Question answer file uploads')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = _('Download a ZIP file including all files that have been uploaded by your customers while creating '
|
||||
'an order.')
|
||||
|
||||
@property
|
||||
def export_form_fields(self):
|
||||
|
||||
@@ -36,7 +36,7 @@ from collections import OrderedDict
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.utils.timezone import get_current_timezone
|
||||
from django.utils.translation import gettext as _, gettext_lazy
|
||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext_lazy
|
||||
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
|
||||
@@ -48,6 +48,8 @@ class CustomerListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'customerlist'
|
||||
verbose_name = gettext_lazy('Customer accounts')
|
||||
organizer_required_permission = 'can_manage_customers'
|
||||
category = pgettext_lazy('export_category', 'Customer accounts')
|
||||
description = gettext_lazy('Download a spreadsheet of all currently registered customer accounts.')
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
|
||||
@@ -27,7 +27,7 @@ import dateutil
|
||||
from django import forms
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext, gettext_lazy
|
||||
from django.utils.translation import gettext, gettext_lazy, pgettext_lazy
|
||||
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import Invoice, OrderPayment
|
||||
@@ -39,6 +39,8 @@ from ..signals import register_data_exporters
|
||||
class DekodiNREIExporter(BaseExporter):
|
||||
identifier = 'dekodi_nrei'
|
||||
verbose_name = 'dekodi NREI (JSON)'
|
||||
category = pgettext_lazy('export_category', 'Invoices')
|
||||
description = gettext_lazy("Download invoices in a format that can be used by the dekodi NREI conversion software.")
|
||||
|
||||
# Specification: http://manuals.dekodi.de/nexuspub/schnittstellenbuch/
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
from django.dispatch import receiver
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from ...control.forms.filter import get_all_payment_providers
|
||||
from ..exporter import ListExporter
|
||||
@@ -45,6 +45,8 @@ from ..signals import register_multievent_data_exporters
|
||||
class EventDataExporter(ListExporter):
|
||||
identifier = 'eventdata'
|
||||
verbose_name = _('Event data')
|
||||
category = pgettext_lazy('export_category', 'Event data')
|
||||
description = _('Download a spreadsheet with information on all events in this organizer account.')
|
||||
|
||||
@cached_property
|
||||
def providers(self):
|
||||
|
||||
@@ -44,7 +44,9 @@ from django.db.models import CharField, Exists, F, OuterRef, Q, Subquery, Sum
|
||||
from django.dispatch import receiver
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import gettext, gettext_lazy as _, pgettext
|
||||
from django.utils.translation import (
|
||||
gettext, gettext_lazy as _, pgettext, pgettext_lazy,
|
||||
)
|
||||
|
||||
from pretix.base.models import Invoice, InvoiceLine, OrderPayment
|
||||
|
||||
@@ -60,6 +62,7 @@ from ..signals import (
|
||||
|
||||
|
||||
class InvoiceExporterMixin:
|
||||
category = pgettext_lazy('export_category', 'Invoices')
|
||||
|
||||
@property
|
||||
def invoice_exporter_form_fields(self):
|
||||
@@ -129,6 +132,7 @@ class InvoiceExporterMixin:
|
||||
class InvoiceExporter(InvoiceExporterMixin, BaseExporter):
|
||||
identifier = 'invoices'
|
||||
verbose_name = _('All invoices')
|
||||
description = _('Download all invoices created by the system as a ZIP file of PDF files.')
|
||||
|
||||
def render(self, form_data: dict, output_file=None):
|
||||
qs = self.invoices_queryset(form_data).filter(shredded=False)
|
||||
@@ -180,6 +184,10 @@ class InvoiceExporter(InvoiceExporterMixin, BaseExporter):
|
||||
class InvoiceDataExporter(InvoiceExporterMixin, MultiSheetListExporter):
|
||||
identifier = 'invoicedata'
|
||||
verbose_name = _('Invoice data')
|
||||
description = _('Download a spreadsheet with the data of all invoices created by the system. The spreadsheet '
|
||||
'includes two sheets, one with a line for every invoice, and one with a line for every position of '
|
||||
'every invoice.')
|
||||
featured = True
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
from django.db.models import Prefetch
|
||||
from django.dispatch import receiver
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from openpyxl.styles import Alignment
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
@@ -48,6 +48,8 @@ def _min(a1, a2):
|
||||
class ItemDataExporter(ListExporter):
|
||||
identifier = 'itemdata'
|
||||
verbose_name = _('Product data')
|
||||
category = pgettext_lazy('export_category', 'Product data')
|
||||
description = _('Download a spreadsheet with details about all products and variations.')
|
||||
|
||||
def iterate_list(self, form_data):
|
||||
locales = self.event.settings.locales
|
||||
|
||||
@@ -38,6 +38,7 @@ from decimal import Decimal
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db.models import Prefetch
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy, pgettext_lazy
|
||||
|
||||
from ..exporter import BaseExporter
|
||||
from ..models import ItemMetaValue, ItemVariation, ItemVariationMetaValue
|
||||
@@ -47,6 +48,9 @@ from ..signals import register_data_exporters
|
||||
class JSONExporter(BaseExporter):
|
||||
identifier = 'json'
|
||||
verbose_name = 'Order data (JSON)'
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = gettext_lazy('Download a structured JSON representation of all orders. This might be useful for the '
|
||||
'import in third-party systems.')
|
||||
|
||||
def render(self, form_data):
|
||||
jo = {
|
||||
|
||||
@@ -36,7 +36,7 @@ from collections import OrderedDict
|
||||
|
||||
from django import forms
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from pretix.base.models import OrderPosition
|
||||
|
||||
@@ -50,6 +50,8 @@ from ..signals import (
|
||||
class MailExporter(BaseExporter):
|
||||
identifier = 'mailaddrs'
|
||||
verbose_name = _('Email addresses (text file)')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = _("Download a text file with all email addresses collected either from buyers or from ticket holders.")
|
||||
|
||||
def render(self, form_data: dict):
|
||||
qs = Order.objects.filter(event__in=self.events, status__in=form_data['status']).prefetch_related('event')
|
||||
|
||||
@@ -47,7 +47,9 @@ from django.db.models.functions import Coalesce
|
||||
from django.dispatch import receiver
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import get_current_timezone, make_aware, now
|
||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext
|
||||
from django.utils.translation import (
|
||||
gettext as _, gettext_lazy, pgettext, pgettext_lazy,
|
||||
)
|
||||
|
||||
from pretix.base.models import (
|
||||
GiftCard, GiftCardTransaction, Invoice, InvoiceAddress, Order,
|
||||
@@ -71,6 +73,11 @@ from ..signals import (
|
||||
class OrderListExporter(MultiSheetListExporter):
|
||||
identifier = 'orderlist'
|
||||
verbose_name = gettext_lazy('Order data')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = gettext_lazy('Download a spreadsheet of all orders. The spreadsheet will include three sheets, one '
|
||||
'with a line for every order, one with a line for every order position, and one with '
|
||||
'a line for every additional fee charged in an order.')
|
||||
featured = True
|
||||
|
||||
@cached_property
|
||||
def providers(self):
|
||||
@@ -776,7 +783,10 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
|
||||
class PaymentListExporter(ListExporter):
|
||||
identifier = 'paymentlist'
|
||||
verbose_name = gettext_lazy('Order payments and refunds')
|
||||
verbose_name = gettext_lazy('Payments and refunds')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = gettext_lazy('Download a spreadsheet of all payments or refunds of every order.')
|
||||
featured = True
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
@@ -855,6 +865,8 @@ class PaymentListExporter(ListExporter):
|
||||
class QuotaListExporter(ListExporter):
|
||||
identifier = 'quotalist'
|
||||
verbose_name = gettext_lazy('Quota availabilities')
|
||||
category = pgettext_lazy('export_category', 'Product data')
|
||||
description = gettext_lazy('Download a spreadsheet of all quotas including their current availability.')
|
||||
|
||||
def iterate_list(self, form_data):
|
||||
has_subevents = self.event.has_subevents
|
||||
@@ -908,6 +920,8 @@ class GiftcardTransactionListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'giftcardtransactionlist'
|
||||
verbose_name = gettext_lazy('Gift card transactions')
|
||||
organizer_required_permission = 'can_manage_gift_cards'
|
||||
category = pgettext_lazy('export_category', 'Gift cards')
|
||||
description = gettext_lazy('Download a spreadsheet of all gift card transactions.')
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
@@ -978,6 +992,8 @@ class GiftcardTransactionListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
class GiftcardRedemptionListExporter(ListExporter):
|
||||
identifier = 'giftcardredemptionlist'
|
||||
verbose_name = gettext_lazy('Gift card redemptions')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = gettext_lazy('Download a spreadsheet of all payments or refunds that involve gift cards.')
|
||||
|
||||
def iterate_list(self, form_data):
|
||||
payments = OrderPayment.objects.filter(
|
||||
@@ -1023,6 +1039,8 @@ class GiftcardListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'giftcardlist'
|
||||
verbose_name = gettext_lazy('Gift cards')
|
||||
organizer_required_permission = 'can_manage_gift_cards'
|
||||
category = pgettext_lazy('export_category', 'Gift cards')
|
||||
description = gettext_lazy('Download a spreadsheet of all gift cards including their current value.')
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
|
||||
@@ -39,6 +39,8 @@ from ..signals import (
|
||||
class WaitingListExporter(ListExporter):
|
||||
identifier = 'waitinglist'
|
||||
verbose_name = _('Waiting list')
|
||||
category = pgettext_lazy('export_category', 'Waiting list')
|
||||
description = _('Download a spread sheet with all your waiting list data.')
|
||||
|
||||
# map selected status to label and queryset-filter
|
||||
status_filters = [
|
||||
|
||||
@@ -4,35 +4,32 @@
|
||||
{% load order_overview %}
|
||||
{% block title %}{% trans "Data export" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>
|
||||
<h1>
|
||||
{% trans "Data export" %}
|
||||
{% if "identifier" in request.GET %}
|
||||
<a href="?" class="btn btn-default">{% trans "Show all" %}</a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% for e in exporters %}
|
||||
<details class="panel panel-default"
|
||||
{% if request.GET.identifier == e.identifier or request.POST.exporter == e.identifier %}open{% endif %}>
|
||||
<summary class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{{ e.verbose_name }}
|
||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||
</h3>
|
||||
</summary>
|
||||
<div id="{{ e.identifier }}">
|
||||
<div class="panel-body">
|
||||
<form action="{% url "control:event.orders.export.do" event=request.event.slug organizer=request.organizer.slug %}"
|
||||
method="post" class="form-horizontal" data-asynctask data-asynctask-download
|
||||
data-asynctask-long>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="exporter" value="{{ e.identifier }}" />
|
||||
{% bootstrap_form e.form layout='control' %}
|
||||
<button class="btn btn-primary pull-right flip" type="submit">
|
||||
<span class="icon icon-upload"></span> {% trans "Start export" %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{% regroup exporters by category as category_list %}
|
||||
{% for c, c_ex in category_list %}
|
||||
{% if c %}
|
||||
<h2>{{ c }}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans "Other exports" %}</h2>
|
||||
{% endif %}
|
||||
<div class="list-group large-link-group">
|
||||
{% for e in c_ex %}
|
||||
<a class="list-group-item" href="?identifier={{ e.identifier }}">
|
||||
<h4>
|
||||
{{ e.verbose_name }}
|
||||
{% if e.featured %}
|
||||
<span class="fa fa-star text-success" data-toggle="tooltip" title="{% trans "Recommended for new users" %}" aria-hidden="true"></span>
|
||||
{% endif %}
|
||||
</h4>
|
||||
{% if e.description %}
|
||||
<p>
|
||||
{{ e.description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load order_overview %}
|
||||
{% block title %}{% trans "Data export" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% trans "Data export" %}
|
||||
{% if exporter %}
|
||||
<small>
|
||||
{{ exporter.verbose_name }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% if exporter.description %}
|
||||
<p class="help-block">{{ exporter.description }}</p>
|
||||
{% endif %}
|
||||
<form action="{% url "control:event.orders.export.do" event=request.event.slug organizer=request.organizer.slug %}"
|
||||
method="post" class="form-horizontal" data-asynctask data-asynctask-download
|
||||
data-asynctask-long>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="exporter" value="{{ exporter.identifier }}"/>
|
||||
{% bootstrap_form exporter.form layout='control' %}
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Start export" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -4,34 +4,27 @@
|
||||
{% load order_overview %}
|
||||
{% block title %}{% trans "Data export" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>
|
||||
<h1>
|
||||
{% trans "Data export" %}
|
||||
{% if "identifier" in request.GET %}
|
||||
<a href="?" class="btn btn-default">{% trans "Show all" %}</a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% for e in exporters %}
|
||||
<details class="panel panel-default" {% if "identifier" in request.GET or "exporter" in request.POST %}open{% endif %}>
|
||||
<summary class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{{ e.verbose_name }}
|
||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||
</h3>
|
||||
</summary>
|
||||
<div id="{{ e.identifier }}">
|
||||
<div class="panel-body">
|
||||
<form action="{% url "control:organizer.export.do" organizer=request.organizer.slug %}"
|
||||
method="post" class="form-horizontal" data-asynctask data-asynctask-download
|
||||
data-asynctask-long>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="exporter" value="{{ e.identifier }}" />
|
||||
{% bootstrap_form e.form layout='control' %}
|
||||
<button class="btn btn-primary pull-right flip" type="submit">
|
||||
<span class="icon icon-upload"></span> {% trans "Start export" %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{% regroup exporters by category as category_list %}
|
||||
{% for c, c_ex in category_list %}
|
||||
{% if c %}
|
||||
<h2>{{ c }}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans "Other exports" %}</h2>
|
||||
{% endif %}
|
||||
<div class="list-group large-link-group">
|
||||
{% for e in c_ex %}
|
||||
<a class="list-group-item" href="?identifier={{ e.identifier }}">
|
||||
<h4>{{ e.verbose_name }}</h4>
|
||||
{% if e.description %}
|
||||
<p>
|
||||
{{ e.description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load order_overview %}
|
||||
{% block title %}{% trans "Data export" %}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>
|
||||
{% trans "Data export" %}
|
||||
{% if exporter %}
|
||||
<small>
|
||||
{{ exporter.verbose_name }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% if exporter.description %}
|
||||
<p class="help-block">{{ exporter.description }}</p>
|
||||
{% endif %}
|
||||
<form action="{% url "control:organizer.export.do" organizer=request.organizer.slug %}"
|
||||
method="post" class="form-horizontal" data-asynctask data-asynctask-download
|
||||
data-asynctask-long>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="exporter" value="{{ exporter.identifier }}"/>
|
||||
{% bootstrap_form exporter.form layout='control' %}
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Start export" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -2237,11 +2237,19 @@ class OrderGo(EventPermissionRequiredMixin, View):
|
||||
class ExportMixin:
|
||||
@cached_property
|
||||
def exporters(self):
|
||||
exporters = []
|
||||
responses = register_data_exporters.send(self.request.event)
|
||||
return sorted(
|
||||
[response(self.request.event, self.request.organizer) for r, response in responses if response],
|
||||
key=lambda ex: (0 if ex.category else 1, ex.category or "", 0 if ex.featured else 1, str(ex.verbose_name).lower())
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def exporter(self):
|
||||
id = self.request.GET.get("identifier") or self.request.POST.get("exporter")
|
||||
for ex in sorted([response(self.request.event, self.request.organizer) for r, response in responses if response], key=lambda ex: str(ex.verbose_name)):
|
||||
if id and ex.identifier != id:
|
||||
if not id:
|
||||
return None
|
||||
for ex in self.exporters:
|
||||
if id != ex.identifier:
|
||||
continue
|
||||
|
||||
# Use form parse cycle to generate useful defaults
|
||||
@@ -2258,12 +2266,12 @@ class ExportMixin:
|
||||
initial=initial
|
||||
)
|
||||
ex.form.fields = ex.export_form_fields
|
||||
exporters.append(ex)
|
||||
return exporters
|
||||
return ex
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['exporters'] = self.exporters
|
||||
ctx['exporter'] = self.exporter
|
||||
return ctx
|
||||
|
||||
|
||||
@@ -2288,16 +2296,6 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, Templ
|
||||
def get_check_url(self, task_id, ajax):
|
||||
return self.request.path + '?async_id=%s&exporter=%s' % (task_id, self.exporter.identifier) + ('&ajax=1' if ajax else '')
|
||||
|
||||
@cached_property
|
||||
def exporter(self):
|
||||
if self.request.method == "POST":
|
||||
identifier = self.request.POST.get("exporter")
|
||||
else:
|
||||
identifier = self.request.GET.get("exporter")
|
||||
for ex in self.exporters:
|
||||
if ex.identifier == identifier:
|
||||
return ex
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'async_id' in request.GET and settings.HAS_CELERY:
|
||||
return self.get_result(request)
|
||||
@@ -2324,7 +2322,11 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, Templ
|
||||
|
||||
class ExportView(EventPermissionRequiredMixin, ExportMixin, TemplateView):
|
||||
permission = 'can_view_orders'
|
||||
template_name = 'pretixcontrol/orders/export.html'
|
||||
|
||||
def get_template_names(self):
|
||||
if self.exporter:
|
||||
return ['pretixcontrol/orders/export_form.html']
|
||||
return ['pretixcontrol/orders/export.html']
|
||||
|
||||
|
||||
class RefundList(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
|
||||
@@ -1507,29 +1507,13 @@ class GiftCardUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
|
||||
class ExportMixin:
|
||||
@cached_property
|
||||
def exporters(self):
|
||||
exporters = []
|
||||
events = self.request.user.get_events_with_permission('can_view_orders', request=self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
responses = register_multievent_data_exporters.send(self.request.organizer)
|
||||
def exporter(self):
|
||||
id = self.request.GET.get("identifier") or self.request.POST.get("exporter")
|
||||
raw_exporters = [
|
||||
response(Event.objects.none() if issubclass(response, OrganizerLevelExportMixin) else events, self.request.organizer)
|
||||
for r, response in responses
|
||||
if response
|
||||
]
|
||||
raw_exporters = [
|
||||
ex for ex in raw_exporters
|
||||
if (
|
||||
not isinstance(ex, OrganizerLevelExportMixin) or
|
||||
self.request.user.has_organizer_permission(self.request.organizer, ex.organizer_required_permission, self.request)
|
||||
)
|
||||
]
|
||||
for ex in sorted(raw_exporters, key=lambda ex: str(ex.verbose_name)):
|
||||
if id and ex.identifier != id:
|
||||
if not id:
|
||||
return None
|
||||
for ex in self.exporters:
|
||||
if id != ex.identifier:
|
||||
continue
|
||||
|
||||
# Use form parse cycle to generate useful defaults
|
||||
test_form = ExporterForm(data=self.request.GET, prefix=ex.identifier)
|
||||
test_form.fields = ex.export_form_fields
|
||||
@@ -1548,8 +1532,8 @@ class ExportMixin:
|
||||
ex.form.fields.update([
|
||||
('events',
|
||||
forms.ModelMultipleChoiceField(
|
||||
queryset=events,
|
||||
initial=events,
|
||||
queryset=self.events,
|
||||
initial=self.events,
|
||||
widget=forms.CheckboxSelectMultiple(
|
||||
attrs={'class': 'scrolling-multiple-choice'}
|
||||
),
|
||||
@@ -1557,11 +1541,37 @@ class ExportMixin:
|
||||
required=True
|
||||
)),
|
||||
])
|
||||
exporters.append(ex)
|
||||
return exporters
|
||||
return ex
|
||||
|
||||
@cached_property
|
||||
def events(self):
|
||||
return self.request.user.get_events_with_permission('can_view_orders', request=self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def exporters(self):
|
||||
responses = register_multievent_data_exporters.send(self.request.organizer)
|
||||
raw_exporters = [
|
||||
response(Event.objects.none() if issubclass(response, OrganizerLevelExportMixin) else self.events, self.request.organizer)
|
||||
for r, response in responses
|
||||
if response
|
||||
]
|
||||
raw_exporters = [
|
||||
ex for ex in raw_exporters
|
||||
if (
|
||||
not isinstance(ex, OrganizerLevelExportMixin) or
|
||||
self.request.user.has_organizer_permission(self.request.organizer, ex.organizer_required_permission, self.request)
|
||||
)
|
||||
]
|
||||
return sorted(
|
||||
raw_exporters,
|
||||
key=lambda ex: (0 if ex.category else 1, ex.category or "", 0 if ex.featured else 1, str(ex.verbose_name).lower())
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['exporter'] = self.exporter
|
||||
ctx['exporters'] = self.exporters
|
||||
return ctx
|
||||
|
||||
@@ -1582,12 +1592,6 @@ class ExportDoView(OrganizerPermissionRequiredMixin, ExportMixin, AsyncAction, T
|
||||
'organizer': self.request.organizer.slug
|
||||
})
|
||||
|
||||
@cached_property
|
||||
def exporter(self):
|
||||
for ex in self.exporters:
|
||||
if ex.identifier == self.request.POST.get("exporter"):
|
||||
return ex
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'async_id' in request.GET and settings.HAS_CELERY:
|
||||
return self.get_result(request)
|
||||
@@ -1621,7 +1625,10 @@ class ExportDoView(OrganizerPermissionRequiredMixin, ExportMixin, AsyncAction, T
|
||||
|
||||
|
||||
class ExportView(OrganizerPermissionRequiredMixin, ExportMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/organizers/export.html'
|
||||
def get_template_names(self):
|
||||
if self.exporter:
|
||||
return ['pretixcontrol/organizers/export_form.html']
|
||||
return ['pretixcontrol/organizers/export.html']
|
||||
|
||||
|
||||
class GateListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, ListView):
|
||||
|
||||
@@ -49,7 +49,7 @@ from django.db import DataError, models
|
||||
from django.db.models import Exists, OuterRef, Q, Subquery
|
||||
from django.db.models.functions import Cast, Coalesce
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.translation import gettext as _, gettext_lazy
|
||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext_lazy
|
||||
from PyPDF2 import PdfMerger, PdfReader, PdfWriter, Transformation
|
||||
from PyPDF2.generic import RectangleObject
|
||||
from reportlab.lib import pagesizes
|
||||
@@ -246,6 +246,9 @@ def render_pdf(event, positions, opt):
|
||||
class BadgeExporter(BaseExporter):
|
||||
identifier = "badges"
|
||||
verbose_name = _("Attendee badges")
|
||||
category = pgettext_lazy('export_category', 'PDF collections')
|
||||
description = gettext_lazy('Download all attendee badges as one large PDF for printing.')
|
||||
featured = True
|
||||
|
||||
@property
|
||||
def export_form_fields(self):
|
||||
|
||||
@@ -45,7 +45,9 @@ from django.db.models.functions import Coalesce, NullIf
|
||||
from django.urls import reverse
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.timezone import is_aware, make_aware
|
||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext
|
||||
from django.utils.translation import (
|
||||
gettext as _, gettext_lazy, pgettext, pgettext_lazy,
|
||||
)
|
||||
from pytz import UTC
|
||||
from reportlab.lib.units import mm
|
||||
from reportlab.platypus import Flowable, Paragraph, Spacer, Table, TableStyle
|
||||
@@ -263,6 +265,9 @@ class PDFCheckinList(ReportlabExportMixin, CheckInListMixin, BaseExporter):
|
||||
name = "overview"
|
||||
identifier = 'checkinlistpdf'
|
||||
verbose_name = gettext_lazy('Check-in list (PDF)')
|
||||
category = pgettext_lazy('export_category', 'Check-in')
|
||||
description = gettext_lazy("Download a PDF version of a check-in list that can be used to check people in at the "
|
||||
"event without digital methods.")
|
||||
|
||||
@property
|
||||
def export_form_fields(self):
|
||||
@@ -420,6 +425,9 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
|
||||
name = "overview"
|
||||
identifier = 'checkinlist'
|
||||
verbose_name = gettext_lazy('Check-in list')
|
||||
category = pgettext_lazy('export_category', 'Check-in')
|
||||
description = gettext_lazy("Download a spreadsheet with all attendees that are included in a check-in list.")
|
||||
featured = True
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
@@ -601,6 +609,9 @@ class CheckinLogList(ListExporter):
|
||||
name = "checkinlog"
|
||||
identifier = 'checkinlog'
|
||||
verbose_name = gettext_lazy('Check-in log (all scans)')
|
||||
category = pgettext_lazy('export_category', 'Check-in')
|
||||
description = gettext_lazy("Download a spreadsheet with one line for every scan that happened at your check-in "
|
||||
"stations.")
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
|
||||
@@ -48,7 +48,9 @@ from django.db.models import DateTimeField, Max, OuterRef, Subquery, Sum
|
||||
from django.template.defaultfilters import floatformat
|
||||
from django.utils.formats import date_format, localize
|
||||
from django.utils.timezone import get_current_timezone, make_aware, now
|
||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext
|
||||
from django.utils.translation import (
|
||||
gettext as _, gettext_lazy, pgettext, pgettext_lazy,
|
||||
)
|
||||
from django_countries.fields import Country
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.enums import TA_CENTER
|
||||
@@ -197,6 +199,9 @@ class OverviewReport(Report):
|
||||
name = "overview"
|
||||
identifier = 'pdfreport'
|
||||
verbose_name = gettext_lazy('Order overview (PDF)')
|
||||
category = pgettext_lazy('export_category', 'Analysis')
|
||||
description = gettext_lazy('Download a PDF version of the key sales numbers per ticket type.')
|
||||
featured = True
|
||||
|
||||
@property
|
||||
def pagesize(self):
|
||||
@@ -382,7 +387,9 @@ class OverviewReport(Report):
|
||||
class OrderTaxListReportPDF(Report):
|
||||
name = "ordertaxlist"
|
||||
identifier = 'ordertaxes'
|
||||
verbose_name = gettext_lazy('List of orders with taxes (PDF)')
|
||||
verbose_name = gettext_lazy('Tax split list (PDF)')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = gettext_lazy("Download a PDF list with the tax amounts included in each order.")
|
||||
|
||||
@property
|
||||
def export_form_fields(self):
|
||||
@@ -553,7 +560,9 @@ class OrderTaxListReportPDF(Report):
|
||||
|
||||
class OrderTaxListReport(MultiSheetListExporter):
|
||||
identifier = 'ordertaxeslist'
|
||||
verbose_name = gettext_lazy('List of orders with taxes')
|
||||
verbose_name = gettext_lazy('Tax split list')
|
||||
category = pgettext_lazy('export_category', 'Order data')
|
||||
description = gettext_lazy("Download a spreadsheet with the tax amounts included in each order.")
|
||||
|
||||
@property
|
||||
def sheets(self):
|
||||
|
||||
@@ -44,7 +44,7 @@ from django.db import DataError, models
|
||||
from django.db.models import OuterRef, Q, Subquery
|
||||
from django.db.models.functions import Cast, Coalesce
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.translation import gettext as _, gettext_lazy
|
||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext_lazy
|
||||
from PyPDF2 import PdfMerger
|
||||
|
||||
from pretix.base.exporter import BaseExporter
|
||||
@@ -63,7 +63,9 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class AllTicketsPDF(BaseExporter):
|
||||
name = "alltickets"
|
||||
verbose_name = gettext_lazy("All PDF tickets in one file")
|
||||
verbose_name = gettext_lazy("Tickets")
|
||||
category = pgettext_lazy('export_category', 'PDF collections')
|
||||
description = gettext_lazy("Download PDF versions of all tickets in your event as one large PDF file.")
|
||||
identifier = "pdfoutput_all_tickets"
|
||||
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user