Allow admins to inspect invoices (#5641)

This is helpful to debug invoice renderers or non-PDF invoices like
Peppol or other XML formats
This commit is contained in:
Raphael Michel
2025-11-19 14:42:18 +01:00
committed by GitHub
parent 9c80f3038a
commit db7518735a
4 changed files with 34 additions and 2 deletions

View File

@@ -362,6 +362,11 @@
</form> </form>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if staff_session %}
<a class="btn btn-default btn-xs admin-only" href="{% url "control:event.order.inspect" event=request.event.slug organizer=request.event.organizer.slug code=order.code id=i.pk %}">
{% trans "Inspect" %}
</a>
{% endif %}
{% if forloop.revcounter0 > 0 %} {% if forloop.revcounter0 > 0 %}
<br/> <br/>
{% endif %} {% endif %}

View File

@@ -391,6 +391,8 @@ urlpatterns = [
name='event.order.retransmitinvoice'), name='event.order.retransmitinvoice'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/reissue$', orders.OrderInvoiceReissue.as_view(), re_path(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/reissue$', orders.OrderInvoiceReissue.as_view(),
name='event.order.reissueinvoice'), name='event.order.reissueinvoice'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/invoices/(?P<id>\d+)/inspect$', orders.OrderInvoiceInspect.as_view(),
name='event.order.inspect'),
re_path(r'^orders/(?P<code>[0-9A-Z]+)/download/(?P<position>\d+)/(?P<output>[^/]+)/$', re_path(r'^orders/(?P<code>[0-9A-Z]+)/download/(?P<position>\d+)/(?P<output>[^/]+)/$',
orders.OrderDownload.as_view(), orders.OrderDownload.as_view(),
name='event.order.download.ticket'), name='event.order.download.ticket'),

View File

@@ -131,13 +131,16 @@ from pretix.control.forms.orders import (
ReactivateOrderForm, ReactivateOrderForm,
) )
from pretix.control.forms.rrule import RRuleForm 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.signals import order_search_forms
from pretix.control.views import PaginationMixin from pretix.control.views import PaginationMixin
from pretix.helpers import OF_SELF from pretix.helpers import OF_SELF
from pretix.helpers.compat import CompatDeleteView from pretix.helpers.compat import CompatDeleteView
from pretix.helpers.format import SafeFormatter, format_map from pretix.helpers.format import SafeFormatter, format_map
from pretix.helpers.hierarkey import clean_filename from pretix.helpers.hierarkey import clean_filename
from pretix.helpers.json import CustomJSONEncoder
from pretix.helpers.safedownload import check_token from pretix.helpers.safedownload import check_token
from pretix.presale.signals import question_form_fields from pretix.presale.signals import question_form_fields
@@ -1752,6 +1755,25 @@ class OrderInvoiceReissue(OrderView):
return HttpResponseNotAllowed(['POST']) 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): class OrderResendLink(OrderView):
permission = 'can_change_orders' permission = 'can_change_orders'

View File

@@ -20,6 +20,7 @@
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
from django.core.files import File from django.core.files import File
from django_countries.fields import Country
from i18nfield.utils import I18nJSONEncoder from i18nfield.utils import I18nJSONEncoder
from phonenumber_field.phonenumber import PhoneNumber from phonenumber_field.phonenumber import PhoneNumber
@@ -36,7 +37,9 @@ class CustomJSONEncoder(I18nJSONEncoder):
return obj.name return obj.name
elif isinstance(obj, LazyI18nStringList): elif isinstance(obj, LazyI18nStringList):
return [s.data for s in obj.data] 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) return str(obj)
else: else:
return super().default(obj) return super().default(obj)