From db7518735adc12aed85276f67378e3887ea0f269 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 19 Nov 2025 14:42:18 +0100 Subject: [PATCH] Allow admins to inspect invoices (#5641) This is helpful to debug invoice renderers or non-PDF invoices like Peppol or other XML formats --- .../templates/pretixcontrol/order/index.html | 5 ++++ src/pretix/control/urls.py | 2 ++ src/pretix/control/views/orders.py | 24 ++++++++++++++++++- src/pretix/helpers/json.py | 5 +++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html index c8fa114fea..2a1cada254 100644 --- a/src/pretix/control/templates/pretixcontrol/order/index.html +++ b/src/pretix/control/templates/pretixcontrol/order/index.html @@ -362,6 +362,11 @@ {% endif %} {% endif %} + {% if staff_session %} + + {% trans "Inspect" %} + + {% endif %} {% if forloop.revcounter0 > 0 %}
{% endif %} diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index 8150aa521d..d310572e30 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -391,6 +391,8 @@ urlpatterns = [ name='event.order.retransmitinvoice'), re_path(r'^orders/(?P[0-9A-Z]+)/invoices/(?P\d+)/reissue$', orders.OrderInvoiceReissue.as_view(), name='event.order.reissueinvoice'), + re_path(r'^orders/(?P[0-9A-Z]+)/invoices/(?P\d+)/inspect$', orders.OrderInvoiceInspect.as_view(), + name='event.order.inspect'), re_path(r'^orders/(?P[0-9A-Z]+)/download/(?P\d+)/(?P[^/]+)/$', orders.OrderDownload.as_view(), name='event.order.download.ticket'), diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index 5abcc88160..e6b4986455 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -131,13 +131,16 @@ from pretix.control.forms.orders import ( ReactivateOrderForm, ) from pretix.control.forms.rrule import RRuleForm -from pretix.control.permissions import EventPermissionRequiredMixin +from pretix.control.permissions import ( + AdministratorPermissionRequiredMixin, EventPermissionRequiredMixin, +) from pretix.control.signals import order_search_forms from pretix.control.views import PaginationMixin from pretix.helpers import OF_SELF from pretix.helpers.compat import CompatDeleteView from pretix.helpers.format import SafeFormatter, format_map from pretix.helpers.hierarkey import clean_filename +from pretix.helpers.json import CustomJSONEncoder from pretix.helpers.safedownload import check_token from pretix.presale.signals import question_form_fields @@ -1752,6 +1755,25 @@ class OrderInvoiceReissue(OrderView): return HttpResponseNotAllowed(['POST']) +class OrderInvoiceInspect(AdministratorPermissionRequiredMixin, OrderView): + + def get(self, *args, **kwargs): # NOQA + inv = get_object_or_404(self.order.invoices, pk=kwargs.get('id')) + d = {"lines": []} + for f in inv._meta.fields: + v = getattr(inv, f.name) + d[f.name] = v + + for il in inv.lines.all(): + line = {} + for f in il._meta.fields: + v = getattr(il, f.name) + line[f.name] = v + d["lines"].append(line) + + return JsonResponse(d, encoder=CustomJSONEncoder) + + class OrderResendLink(OrderView): permission = 'can_change_orders' diff --git a/src/pretix/helpers/json.py b/src/pretix/helpers/json.py index c3ec849a8b..195c124a39 100644 --- a/src/pretix/helpers/json.py +++ b/src/pretix/helpers/json.py @@ -20,6 +20,7 @@ # . # from django.core.files import File +from django_countries.fields import Country from i18nfield.utils import I18nJSONEncoder from phonenumber_field.phonenumber import PhoneNumber @@ -36,7 +37,9 @@ class CustomJSONEncoder(I18nJSONEncoder): return obj.name elif isinstance(obj, LazyI18nStringList): return [s.data for s in obj.data] - if isinstance(obj, PhoneNumber): + elif isinstance(obj, PhoneNumber): + return str(obj) + elif isinstance(obj, Country): return str(obj) else: return super().default(obj)