WalletPlatform.{is_enabled,is_available,is_available_for_position}; cleanups; refactoring

This commit is contained in:
Kara Engelhardt committed 2026-11-05 13:22:46 +01:00
1 parent 97a448f1d0
commit 8ef6fccf21
18 files changed
+245 -132

No files matched your search

+16 -8
View File
@@ -297,12 +297,20 @@ def get_download_buttons(event, show_disabled):
return buttons
def get_wallet_buttons(event):
# TODO(wallet): implement this
from pretix.plugins.wallet.platforms import AVAILABLE_PLATFORMS
buttons = []
for p in AVAILABLE_PLATFORMS:
platform = p(event)
attr, cont = platform.render_download_button()
buttons.append({"identifier": platform.identifier, "attributes": attr, "content": cont})
def get_wallet_buttons(event: Event, positions: list[OrderPosition], show_disabled: bool):
from pretix.plugins.wallet.platforms import get_available_platforms
platforms = get_available_platforms(event, show_disabled)
buttons = {"combined": []}
for platform in platforms:
if any(platform.is_available_for_position(pos) for pos in positions):
attr, cont = platform.render_download_button()
buttons["combined"].append({"identifier": platform.identifier, "attributes": attr, "content": cont})
for position in positions:
buttons[position] = []
for platform in platforms:
if platform.is_available_for_position(position):
attr, cont = platform.render_download_button()
buttons[position].append({"identifier": platform.identifier, "attributes": attr, "content": cont})
return buttons
@@ -575,7 +575,7 @@
</button>
</form>
{% endfor %}
{% for b in wallet_buttons %}
{% for b in wallet_buttons|getitem:line %}
{% comment %} TODO(wallet): move view to core {% endcomment %}
<form action="{% url "plugins:wallet:event.order.wallet.get" code=order.code event=request.event.slug organizer=request.event.organizer.slug position=line.pk platform=b.identifier %}"
method="post" data-asynctask data-asynctask-download
+4 -11
View File
@@ -544,7 +544,8 @@ class OrderDetail(OrderView):
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['items'] = self.get_items()
items = self.get_items()
ctx['items'] = items
ctx['has_cancellation_fee'] = any(f.fee_type == OrderFee.FEE_TYPE_CANCELLATION for f in ctx['items']['fees'])
ctx['event'] = self.request.event
ctx['payments'] = self.order.payments.order_by('-created')
@@ -566,8 +567,8 @@ class OrderDetail(OrderView):
pending_sum = self.order.pending_sum
ctx['overpaid'] = pending_sum * -1
ctx['download_buttons'] = self.download_buttons
ctx['wallet_buttons'] = self.wallet_buttons
ctx['download_buttons'] = get_download_buttons(self.request.event, show_disabled=True)
ctx['wallet_buttons'] = get_wallet_buttons(self.request.event, items['positions'], show_disabled=True)
ctx['payment_refund_sum'] = self.order.payment_refund_sum
ctx['pending_sum'] = pending_sum
ctx['uncancelled_invoice'] = self.order.invoices.exclude(
@@ -576,14 +577,6 @@ class OrderDetail(OrderView):
return ctx
@cached_property
def download_buttons(self):
return get_download_buttons(self.request.event, show_disabled=True)
@cached_property
def wallet_buttons(self):
return get_wallet_buttons(self.request.event)
def get_items(self):
queryset = self.object.all_positions
+9 -7
View File
@@ -8,13 +8,11 @@ from rest_framework import serializers, viewsets
from pretix.api.serializers.i18n import I18nAwareModelSerializer
from .models import WalletLayout, WalletPlatformLayout
from .platforms import AVAILABLE_PLATFORMS, AVAILABLE_STYLES_DICT
from .platforms import get_available_platforms, AVAILABLE_STYLES_DICT
class WalletPlatformLayoutSerializer(I18nAwareModelSerializer):
platform = serializers.ChoiceField(
choices=[p.identifier for p in AVAILABLE_PLATFORMS]
)
platform = serializers.ChoiceField(choices=[])
style = serializers.CharField(allow_null=True, required=False)
file_settings = serializers.JSONField(default=dict, required=False)
@@ -22,6 +20,13 @@ class WalletPlatformLayoutSerializer(I18nAwareModelSerializer):
model = WalletPlatformLayout
fields = ("platform", "style", "layout", "file_settings")
def get_fields(self):
fields = super().get_fields()
fields["platform"].choices = [
p.identifier for p in get_available_platforms(self.context["event"], show_disabled=True)
]
return fields
def validate_layout(self, value):
if not isinstance(value, dict):
raise ValidationError(_("Layout must be a dict"))
@@ -70,9 +75,6 @@ class WalletLayoutSerializer(I18nAwareModelSerializer):
fields = ("id", "name", "platform_layouts")
read_only_fields = ("id",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
super().save(*args, **kwargs, event=self.context["event"])
+3
View File
@@ -54,6 +54,9 @@ class WalletLayout(LoggedModel):
"name",
)
def __str__(self):
return self.name
class WalletPlatformLayout(LoggedModel):
parent = models.ForeignKey(
@@ -6,7 +6,18 @@ from .google import (
GoogleWalletDefaultEventTicket,
)
AVAILABLE_PLATFORMS: list[type[WalletPlatform]] = [ApplePlatform, GooglePlatform]
# TODO(wallet): replace with registry or similar
PLATFORMS: list[type[WalletPlatform]] = [ApplePlatform, GooglePlatform]
def get_available_platforms(event, show_disabled: bool = False):
platforms = []
for p in PLATFORMS:
platform = p(event)
if platform.is_available()[0] and (show_disabled or platform.is_enabled()):
platforms.append(platform)
return platforms
AVAILABLE_STYLES: dict[str, list[type[PassStyle]]] = {
"apple": [AppleWalletEventTicket],
@@ -23,7 +34,7 @@ def get_style(platform: str, identifier: str) -> type[PassStyle] | None:
__all__ = [
"AVAILABLE_PLATFORMS",
"get_available_platforms",
"AVAILABLE_STYLES",
"PassStyle",
"WalletPlatform",
@@ -1,3 +1,4 @@
from collections import OrderedDict
import hashlib
import io
import json
@@ -24,7 +25,6 @@ from ...models import CombinedAppleWalletPass
from django.core.files.base import ContentFile
from django import forms
from django.utils.translation import gettext as _
from pretix.base.forms import SecretKeySettingsField
from pretix.control.forms import ClearableBasenameFileInput
@@ -101,24 +101,43 @@ class ApplePlatform(WalletPlatform):
def generate(self, position, layout=None) -> str:
if not layout:
layout = self.get_layout(position).pass_layout
pass_obj = layout.generate(position)
op_layout = self.get_layout(position)
if not op_layout:
raise ValueError(
_(
"WalletPlatform.generate called without layout and without position layout"
)
)
layout = op_layout.pass_layout
layout.generate(position)
return eventreverse_absolute(
self.event,
"plugins:wallet:apple_download",
kwargs={"order": position.order.code, "secret": position.order.secret, "position": position.pk},
kwargs={
"order": position.order.code,
"secret": position.order.secret,
"position": position.pk,
},
)
def generate_order(self, order: Order):
with tempfile.TemporaryFile() as d:
with zipfile.ZipFile(d, "w") as zipf:
for pos in order.positions_with_tickets:
pass_obj = self.get_layout(pos).pass_layout.generate(pos)
zipf.writestr(
"{}-{}.pkpass".format(order.code, pos.positionid),
pass_obj.content.read(),
)
if self.is_available_for_position(pos):
layout = self.get_layout(pos)
if not layout:
raise ValueError(
"Impossible: is_available_for_position==True but no layout"
)
pass_obj = layout.pass_layout.generate(pos)
zipf.writestr(
"{}-{}.pkpass".format(order.code, pos.positionid),
pass_obj.content.read(),
)
d.seek(0)
data = d.read()
@@ -130,7 +149,9 @@ class ApplePlatform(WalletPlatform):
order=order,
file=None,
)
ct.file.save("{}-{}.pkpasses".format(order.code, self.identifier), ContentFile(data))
ct.file.save(
"{}-{}.pkpasses".format(order.code, self.identifier), ContentFile(data)
)
return eventreverse_absolute(
self.event,
@@ -138,6 +159,19 @@ class ApplePlatform(WalletPlatform):
kwargs={"order": order.code, "secret": order.secret},
)
def is_available(self):
for field in [
"wallet_apple_team_id",
"wallet_apple_pass_type_id",
"wallet_apple_certificate",
"wallet_apple_ca_certificate",
"wallet_apple_key",
]:
if not self.event.settings.get(field):
return (False, _("Missing field: {field}").format(field=field))
return super().is_available()
class StringResource:
entries: dict[str, MaybeTranslatedString]
locales: set[str]
+30 -15
View File
@@ -1,16 +1,16 @@
import enum
from functools import cached_property
from typing import Iterable, TypedDict
from typing import TypedDict
import jsonschema
from django.core.exceptions import ValidationError
from django.core.files import File
from django.shortcuts import get_object_or_404
from i18nfield.strings import LazyI18nString
from pretix.api.helpers import handle_file_upload
from pretix.base.models import OrderPosition
from pretix.base.models.orders import Order
from pretix.base.settings import SettingsSandbox
from pretix.plugins.wallet.models import WalletPlatformLayout
from ..i18n import MaybeTranslatedString, localizable_to_dict
@@ -24,10 +24,27 @@ from .settings import SettingsField, SettingsFile
from django.utils.translation import gettext as _
from django.utils.html import format_html
class WalletPlatform:
identifier: str
name: str
# TODO: register urls here?
def __init__(self, event):
self.event = event
self.wallet_settings = SettingsSandbox('ticketoutput', 'wallet', event)
def is_enabled(self):
if not self.wallet_settings.get('_enabled', as_type=bool):
return False
return True
def is_available(self) -> tuple[bool, str | None]:
return (True, None)
def is_available_for_position(self, op: OrderPosition):
return op.generate_ticket and bool(self.get_layout(op))
@classmethod
def get_global_settings(cls, **kwargs):
"""
@@ -43,19 +60,19 @@ class WalletPlatform:
attr: the html attributes that should be added to the button element as a dict[str, str] or None
content: the content of the button
"""
return None, format_html('<span class="fa fa-download"></span> {}', _('Add to {wallet}').format(wallet=self.name))
return None, format_html(
'<span class="fa fa-download"></span> {}',
_("Add to {wallet}").format(wallet=self.name),
)
def get_layout(self, op):
def get_layout(self, op) -> WalletPlatformLayout | None:
if hasattr(op.item, "walletlayout"):
wallet_layout = op.item.walletlayout.layout
else:
wallet_layout = op.event.wallet_layouts.get(default=True)
platform_layout: WalletPlatformLayout = get_object_or_404(
wallet_layout.platform_layouts, platform=self.identifier
)
return platform_layout
return wallet_layout.platform_layouts.filter(platform=self.identifier).first()
def generate(self, position, layout=None) -> str:
def generate(self, position, layout: "PassStyle | None"=None) -> str:
"""
This method should generate the wallet pass and return a url the user should be sent
to to retrieve that pass (e.g. via download or by redirecting to the wallet provider)
@@ -64,7 +81,10 @@ class WalletPlatform:
if the pass content has changed.
"""
if not layout:
layout = self.get_layout(position).pass_layout
op_layout = self.get_layout(position)
if not op_layout:
raise ValueError(_("WalletPlatform.generate called without layout and without position layout"))
layout = op_layout.pass_layout
return layout.generate(position)
def generate_order(self, order: Order) -> str:
@@ -78,11 +98,6 @@ class WalletPlatform:
"""
raise NotImplementedError()
# TODO: register urls here?
def __init__(self, event):
self.event = event
# TODO: is_available : check if all config for platform is set
class LayoutContext(TypedDict):
placeholders: dict[str, dict]
@@ -1,7 +1,7 @@
import json
import uuid
from functools import cached_property
from typing import Iterable, OrderedDict
from typing import OrderedDict
from django.conf import settings
from django.db import transaction
@@ -202,7 +202,11 @@ class GooglePlatform(WalletPlatform):
def generate(self, position, layout: PassStyle | None = None):
# TODO?: early-exit caching (if object for position exists and layout is None)
if not layout:
layout = self.get_layout(position).pass_layout
op_layout = self.get_layout(position)
if not op_layout:
raise ValueError(_("WalletPlatform.generate called without layout and without position layout"))
layout = op_layout.pass_layout
class_object, ticket_object = layout.generate(position)
self.put_item_cached(class_object)
@@ -212,9 +216,11 @@ class GooglePlatform(WalletPlatform):
class_objects = []
ticket_objects = []
for position in order.positions_with_tickets:
class_object, ticket_object = self.get_layout(
position
).pass_layout.generate(position)
layout = self.get_layout(position)
if not layout:
raise ValueError("Impossible: is_available_for_position==True but no layout")
class_object, ticket_object = layout.generate(position)
class_objects.append(class_object)
ticket_objects.append(ticket_object)
@@ -222,3 +228,9 @@ class GooglePlatform(WalletPlatform):
self.put_item_cached(co)
return self._get_jwt(ticket_objects)
def is_available(self):
for field in ["wallet_google_issuer_id", "wallet_google_credentials"]:
if not self.event.settings.get(field):
return (False, _("Missing field: {field}").format(field=field))
return super().is_available()
+6 -6
View File
@@ -34,7 +34,7 @@ from pretix.control.signals import item_forms
from .forms import WalletLayoutItemForm
from .models import WalletLayoutItem
from .ticketoutput import WalletSettingsHolder
from .platforms import AVAILABLE_PLATFORMS
from .platforms import PLATFORMS
from .tasks import send_update_apns
from .models import AppleWalletPass, CombinedAppleWalletPass
from .tasks import get_pass
@@ -42,13 +42,12 @@ from .models import GoogleWalletInstance
from .platforms.google.google_wallet import Resource
@receiver(register_ticket_outputs, dispatch_uid="output_wallet")
def register_output(sender, **kwargs):
return WalletSettingsHolder
for platform in AVAILABLE_PLATFORMS:
for platform in PLATFORMS:
if hasattr(platform, "get_global_settings"):
register_global_settings.connect(
platform.get_global_settings,
@@ -74,12 +73,12 @@ def control_item_forms(sender, request, item, **kwargs):
return forms
@receiver(periodic_task, dispatch_uid="wallet_periodic")
def periodic_tasks(sender, **kwargs):
# TODO: move to platform?
send_update_apns.apply_async()
# TODO: move to platform?
@receiver(invalidate_ticket_cache, dispatch_uid="invalidate_ticket_cache_wallet_apple")
def invalidate_apple(
@@ -106,6 +105,7 @@ def invalidate_apple(
"model": "orderposition",
"pk": pass_obj.order_position_id,
"platform_identifier": "apple",
"show_disabled": False
}
)
@@ -113,7 +113,6 @@ def invalidate_apple(
passes_obj.delete()
@receiver(invalidate_ticket_cache, dispatch_uid="invalidate_ticket_cache_wallet_google")
def invalidate_google(
sender: Event, item: int | None, provider: str | None, order: int | None, **kwargs
@@ -137,5 +136,6 @@ def invalidate_google(
"model": "orderposition",
"pk": inst.order_position_id,
"platform_identifier": "google",
"show_disabled": False
}
)
)
+8 -8
View File
@@ -5,9 +5,9 @@ import ssl
import httpx
import tempfile
from django.utils.timezone import now
from django.db.models import OuterRef, Q, Exists
from django.db.models import OuterRef, Exists
from pretix.plugins.wallet.platforms import AVAILABLE_PLATFORMS
from pretix.plugins.wallet.platforms import get_available_platforms
from pretix.plugins.wallet.platforms.base import WalletPlatform
from .models import AppleWalletPass, AppleWalletDevice
from django_scopes import scopes_disabled
@@ -73,17 +73,17 @@ def send_update_apns():
device.save()
def get_platform(event, platform) -> WalletPlatform | None:
for p in AVAILABLE_PLATFORMS:
def get_platform(event, platform, show_disabled) -> WalletPlatform | None:
for p in get_available_platforms(event, show_disabled):
if p.identifier == platform:
return p(event)
return p
@app.task(base=ProfiledTask)
def get_pass(model: str, pk: int, platform_identifier: str):
def get_pass(model: str, pk: int, platform_identifier: str, show_disabled: bool):
if model == "order":
order = Order.objects.select_related("event").get(id=pk)
platform = get_platform(order.event, platform_identifier)
platform = get_platform(order.event, platform_identifier, show_disabled)
if not platform:
return
return platform.generate_order(order)
@@ -91,7 +91,7 @@ def get_pass(model: str, pk: int, platform_identifier: str):
position = OrderPosition.objects.select_related("order", "order__event").get(
id=pk
)
platform = get_platform(position.order.event, platform_identifier)
platform = get_platform(position.order.event, platform_identifier, show_disabled)
if not platform:
return
return platform.generate(position)
+3 -4
View File
@@ -23,7 +23,6 @@ from django.urls import re_path
from pretix.api.urls import event_router
from pretix.plugins.wallet.views.google import CallbackView
import pretix
from .api import WalletLayoutViewSet
from .views.apple import (
@@ -111,7 +110,7 @@ event_patterns = [
name="google_webhook",
),
re_path(
r"^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/download/(?P<position>[0-9]+)/(?P<platform>[^/]+)$",
r"^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/wallet/download/(?P<position>[0-9]+)/(?P<platform>[^/]+)$",
PresaleWalletGetPass.as_view(),
name="presale_event.order.wallet.get",
),
@@ -126,12 +125,12 @@ event_patterns = [
name="apple_download_combined",
),
re_path(
r"^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/download/(?P<platform>[^/]+)$",
r"^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/wallet/download/(?P<platform>[^/]+)$",
PresaleWalletGetPass.as_view(),
name="presale_event.order.wallet.get.combined",
),
re_path(
r"^ticket/(?P<order>[^/]+)/(?P<position>\d+)/(?P<secret>[A-Za-z0-9]+)/download/(?P<pid>[0-9]+)/(?P<platform>[^/]+)$",
r"^ticket/(?P<order>[^/]+)/(?P<position>\d+)/(?P<secret>[A-Za-z0-9]+)/wallet/download/(?P<pid>[0-9]+)/(?P<platform>[^/]+)$",
PresaleWalletGetPassPosition.as_view(),
name="presale_event.order.position.wallet.get",
),
+13 -9
View File
@@ -38,7 +38,7 @@ from ..placeholders import (
get_wallet_placeholders,
)
from ..platforms import (
AVAILABLE_PLATFORMS,
get_available_platforms,
AVAILABLE_STYLES,
AVAILABLE_STYLES_DICT,
)
@@ -97,7 +97,9 @@ class LayoutEditorView(LayoutDetailView):
for style in AVAILABLE_STYLES.get(platform.identifier, [])
},
}
for platform in AVAILABLE_PLATFORMS
for platform in get_available_platforms(
self.request.event, show_disabled=True
)
]
context["placeholders"] = get_editor_placeholders(self.request.event)
context["locales"] = {
@@ -196,9 +198,10 @@ class LayoutPreviewView(EventPermissionRequiredMixin, View):
base_file_settings = {}
platform = None
for p in AVAILABLE_PLATFORMS:
for p in get_available_platforms(event, show_disabled=True):
if p.identifier == platform_id:
platform = p(event)
platform = p
if not platform:
raise BadRequest("Unknown platform")
if style_id not in AVAILABLE_STYLES_DICT[platform_id]:
@@ -280,6 +283,7 @@ class LayoutDelete(WalletLayoutMixin, DeleteView):
messages.success(self.request, _("The selected layout been deleted."))
return redirect(self.get_success_url())
class OrderDownloadMixin:
task = get_pass
@@ -291,9 +295,9 @@ class OrderDownloadMixin:
@cached_property
def platform(self):
for p in AVAILABLE_PLATFORMS:
for p in get_available_platforms(self.request.event, show_disabled=True):
if p.identifier == self.kwargs.get("platform"):
return p(self.request.event)
return p
class WalletGetView(OrderDownloadMixin, AsyncAction, OrderView):
@@ -318,10 +322,10 @@ class WalletGetView(OrderDownloadMixin, AsyncAction, OrderView):
)
if "position" in kwargs:
if not self.order_position.generate_ticket:
if not self.platform.is_available_for_position(self.order_position):
return self.error(_("Ticket download is not enabled for this product."))
return self.do(
"orderposition", self.order_position.pk, self.platform.identifier
"orderposition", self.order_position.pk, self.platform.identifier, True
)
else:
return self.do("order", self.order.pk, self.platform.identifier)
return self.do("order", self.order.pk, self.platform.identifier, True)
+22 -9
View File
@@ -16,13 +16,26 @@ from pretix.presale.views import EventViewMixin
from pretix.presale.views.order import (
OrderDetailMixin, OrderPositionDetailMixin,
)
from .control import OrderDownloadMixin
from pretix.plugins.wallet.platforms import get_available_platforms
from pretix.plugins.wallet.tasks import get_pass
class PresaleOrderDownloadMixin(OrderDownloadMixin):
class OrderDownloadMixin:
task = get_pass
known_errortypes = ['OrderError']
def get_success_message(self, value):
return ""
def get_success_url(self, value):
return value
@cached_property
def platform(self):
for p in get_available_platforms(self.request.event, show_disabled=False):
if p.identifier == self.kwargs.get("platform"):
return p
def post(self, request, *args, **kwargs):
# TODO: check if available if is_available is implemented (or check in super.platform?)
if not self.platform:
@@ -43,17 +56,17 @@ class PresaleOrderDownloadMixin(OrderDownloadMixin):
return self.error(OrderError(_('Please click the link we sent you via email to download your tickets.')))
if "position" in kwargs:
if not self.order_position.generate_ticket:
return self.error(_("Ticket download is not enabled for this product."))
if not self.platform.is_available_for_position(self.order_position):
return self.error(OrderError(_("Ticket download is not enabled for this product.")))
return self.do(
"orderposition", self.order_position.pk, self.platform.identifier
"orderposition", self.order_position.pk, self.platform.identifier, False
)
else:
return self.do("order", self.order.pk, self.platform.identifier)
return self.do("order", self.order.pk, self.platform.identifier, False)
@method_decorator(xframe_options_exempt, 'dispatch')
class PresaleWalletGetPass(PresaleOrderDownloadMixin, EventViewMixin, OrderDetailMixin, AsyncAction, View):
class PresaleWalletGetPass(OrderDownloadMixin, EventViewMixin, OrderDetailMixin, AsyncAction, View):
def get_error_url(self):
return self.get_order_url()
@@ -72,7 +85,7 @@ class PresaleWalletGetPass(PresaleOrderDownloadMixin, EventViewMixin, OrderDetai
@method_decorator(xframe_options_exempt, 'dispatch')
class PresaleWalletGetPassPosition(PresaleOrderDownloadMixin, EventViewMixin, OrderPositionDetailMixin, AsyncAction, View):
class PresaleWalletGetPassPosition(OrderDownloadMixin, EventViewMixin, OrderPositionDetailMixin, AsyncAction, View):
def get_error_url(self):
return self.get_position_url()
@@ -5,6 +5,8 @@
{% load safelink %}
{% load rich_text %}
{% load money %}
{% load getitem %}
{% blocktrans asvar s_taxes %}taxes{% endblocktrans %}
<div role="table" aria-label="{% trans "Your cart" %}" aria-describedby="{% if cart.is_ordered %}cart-description{% else%}cart-deadline{% endif %}" aria-rowcount="{{ cart.positions|length|add:2 }}">
<div class="sr-only" role="rowgroup">
@@ -220,36 +222,7 @@
{% if download %}
<div role="cell" class="download-desktop">
{% if line in tickets_with_download %}
{% for b in download_buttons %}
<form action="{% if position_page and line.addon_to %}{% eventurl event "presale:event.order.position.download" secret=line.addon_to.web_secret order=order.code output=b.identifier pid=line.pk position=line.addon_to.positionid %}{% elif position_page %}{% eventurl event "presale:event.order.position.download" secret=line.web_secret order=order.code output=b.identifier pid=line.pk position=line.positionid %}{% else %}{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier position=line.pk %}{% endif %}"
method="post" data-asynctask data-asynctask-download class="download-btn-form{% if b.javascript_required or b.confirmation_text %} requirejs{% endif %}">
{% csrf_token %}
<button type="submit"
class="btn btn-sm {% if b.identifier == "pdf" %}btn-primary{% else %}btn-default{% endif %}"
{% if b.confirmation_text %}data-confirmation-text="{{ b.confirmation_text|rich_text|force_escape }}"{% endif %}>
<span class="fa {{ b.icon }}" aria-hidden="true"></span> {{ b.text }}
</button>
</form>
{% endfor %}
{% for b in wallet_buttons %}
{% comment %} TODO(wallet): move view to core {% endcomment %}
<form
action="{% if position_page and line.addon_to %}
{% eventurl event "plugins:wallet:presale_event.order.position.wallet.get" secret=line.addon_to.web_secret order=order.code platform=b.identifier pid=line.pk position=line.addon_to.positionid %}
{% elif position_page %}
{% eventurl event "plugins:wallet:presale_event.order.position.wallet.get" secret=line.web_secret order=order.code platform=b.identifier pid=line.pk position=line.positionid %}
{% else %}
{% eventurl event "plugins:wallet:presale_event.order.wallet.get" secret=order.secret order=order.code platform=b.identifier position=line.pk %}
{% endif %}"
method="post" data-asynctask data-asynctask-download class="download-btn-form">
{% csrf_token %}
<button type="submit"
class="btn btn-sm btn-default {{ b.attributes.class }}"
{% include "pretixbase/fragments/attributes.html" with attributes=b.attributes %}>
{{ b.content }}
</button>
</form>
{% endfor %}
{% include "pretixpresale/event/fragment_item_downloads.html" with line=line %}
{% endif %}
</div>
{% elif line.addon_to %}
@@ -1,6 +1,8 @@
{% load i18n %}
{% load eventurl %}
{% load rich_text %}
{% load getitem %}
{% if download_email_required %}
<div class="panel panel-primary">
<div class="panel-heading">
@@ -55,7 +57,7 @@
</form>
{% endif %}
{% endfor %}
{% for b in wallet_buttons %}
{% for b in wallet_buttons.combined %}
{# TODO(wallet): move view to core #}
<form action="{% eventurl event "plugins:wallet:presale_event.order.wallet.get.combined" secret=order.secret order=order.code platform=b.identifier %}"
method="post" data-asynctask data-asynctask-download class="download-btn-form">
@@ -75,7 +77,7 @@
</p>
{% elif tickets_with_download|length == 1 %}
<div>
{% for b in download_buttons %}
{% comment %} {% for b in download_buttons %}
<form action="{% if position_page and tickets_with_download.0.addon_to %}{% eventurl event "presale:event.order.position.download" secret=tickets_with_download.0.addon_to.web_secret order=order.code output=b.identifier pid=tickets_with_download.0.pk position=tickets_with_download.0.addon_to.positionid %}{% elif position_page %}{% eventurl event "presale:event.order.position.download" secret=tickets_with_download.0.web_secret order=order.code output=b.identifier pid=tickets_with_download.0.pk position=tickets_with_download.0.positionid %}{% else %}{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier position=tickets_with_download.0.pk %}{% endif %}"
method="post" data-asynctask data-asynctask-download
class="download-btn-form {% if b.javascript_required or b.confirmation_text %}requirejs{% endif %}">
@@ -87,8 +89,10 @@
</button>
</form>
{% endfor %}
{% for b in wallet_buttons %}
{% comment %} TODO(wallet): move view to core {% endcomment %}
{% for b in wallet_buttons|getitem:tickets_with_download.0 %}
TODO(wallet): move view to core {% endcomment %}
{% include "pretixpresale/event/fragment_item_downloads.html" with line=tickets_with_download.0 button_size="lg" download_text="long_text" %}
{% comment %}
<form
action="{% if position_page and tickets_with_download.0.addon_to %}
{% eventurl event "plugins:wallet:presale_event.order.position.wallet.get" secret=tickets_with_download.0.addon_to.web_secret order=order.code platform=b.identifier pid=tickets_with_download.0.pk position=tickets_with_download.0.addon_to.positionid %}
@@ -105,7 +109,7 @@
{{ b.content }}
</button>
</form>
{% endfor %}
{% endfor %} {% endcomment %}
</div>
<p class="help-block">
{% blocktrans trimmed %}
@@ -0,0 +1,41 @@
{% load i18n %}
{% load icon %}
{% load eventurl %}
{% load daterange %}
{% load safelink %}
{% load rich_text %}
{% load money %}
{% load getitem %}
{% for b in download_buttons %}
<form action="{% if position_page and line.addon_to %}{% eventurl event "presale:event.order.position.download" secret=line.addon_to.web_secret order=order.code output=b.identifier pid=line.pk position=line.addon_to.positionid %}{% elif position_page %}{% eventurl event "presale:event.order.position.download" secret=line.web_secret order=order.code output=b.identifier pid=line.pk position=line.positionid %}{% else %}{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier position=line.pk %}{% endif %}"
method="post" data-asynctask data-asynctask-download class="download-btn-form{% if b.javascript_required or b.confirmation_text %} requirejs{% endif %}">
{% csrf_token %}
<button type="submit"
class="btn btn-{{ button_size|default:"sm" }} {% if b.identifier == "pdf" %}btn-primary{% else %}btn-default{% endif %}"
{% if b.confirmation_text %}data-confirmation-text="{{ b.confirmation_text|rich_text|force_escape }}"{% endif %}>
{% with download_text=download_text|default:"text" %}
<span class="fa {{ b.icon }}" aria-hidden="true"></span> {{ b|getitem:download_text }}
{% endwith %}
</button>
</form>
{% endfor %}
{% for b in wallet_buttons|getitem:line %}
{% comment %} TODO(wallet): move views to core {% endcomment %}
<form
action="{% spaceless %}{% if position_page and line.addon_to %}
{% eventurl event "plugins:wallet:presale_event.order.position.wallet.get" secret=line.addon_to.web_secret order=order.code platform=b.identifier pid=line.pk position=line.addon_to.positionid %}
{% elif position_page %}
{% eventurl event "plugins:wallet:presale_event.order.position.wallet.get" secret=line.web_secret order=order.code platform=b.identifier pid=line.pk position=line.positionid %}
{% else %}
{% eventurl event "plugins:wallet:presale_event.order.wallet.get" secret=order.secret order=order.code platform=b.identifier position=line.pk %}
{% endif %}{% endspaceless %}"
method="post" data-asynctask data-asynctask-download class="download-btn-form">
{% csrf_token %}
<button type="submit"
class="btn btn-{{ button_size|default:"sm" }} btn-default {{ b.attributes.class }}"
{% include "pretixbase/fragments/attributes.html" with attributes=b.attributes %}>
{{ b.content }}
</button>
</form>
{% endfor %}
+3 -2
View File
@@ -259,7 +259,7 @@ class TicketPageMixin:
order=self.order
)
ctx['tickets_with_download'] = [p for p in ctx['cart']['positions'] if p in positions_with_tickets]
ctx['tickets_with_download'] = [p for p in ctx['cart']['positions'] if p in positions_with_tickets] # TODO(wallet): can this just be simplyfied to 'positions_with_tickets'
ctx['download_buttons'] = self.download_buttons
ctx['wallet_buttons'] = self.wallet_buttons
@@ -274,7 +274,8 @@ class TicketPageMixin:
@cached_property
def wallet_buttons(self):
return get_wallet_buttons(self.request.event)
return get_wallet_buttons(self.request.event, self.order.positions_with_tickets, show_disabled=False)
@method_decorator(xframe_options_exempt, 'dispatch')
class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TicketPageMixin, TemplateView):