Let plugins allow/prevent the download of individual tickets in an order (#3836)

(extends the functionality of the allow_ticket_download signal)
This commit is contained in:
Mira
2024-02-01 17:45:58 +01:00
committed by GitHub
parent 4f4fcb84ce
commit e20edab98f
11 changed files with 140 additions and 125 deletions

View File

@@ -44,7 +44,7 @@ from datetime import datetime, time, timedelta
from decimal import Decimal
from functools import reduce
from time import sleep
from typing import Any, Dict, List, Union
from typing import Any, Dict, Iterable, List, Union
from zoneinfo import ZoneInfo
import dateutil
@@ -79,7 +79,7 @@ from pretix.base.i18n import language
from pretix.base.models import Customer, User
from pretix.base.reldate import RelativeDateWrapper
from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.signals import order_gracefully_delete
from pretix.base.signals import allow_ticket_download, order_gracefully_delete
from ...helpers import OF_SELF
from ...helpers.countries import CachedCountries, FastCountryField
@@ -1137,12 +1137,19 @@ class Order(LockModel, LoggedModel):
attach_tickets=True,
)
@property
def positions_with_tickets_ignoring_plugins(self):
return (op for op in self.positions.select_related('item') if op.generate_ticket)
@property
def positions_with_tickets(self):
for op in self.positions.select_related('item'):
if not op.generate_ticket:
continue
yield op
signal_response = allow_ticket_download.send(self.event, order=self)
if all([r is True for rr, r in signal_response]):
return self.positions_with_tickets_ignoring_plugins
elif any([r is False for rr, r in signal_response]):
return []
else:
return set.intersection(set(self.positions_with_tickets_ignoring_plugins), *[set(r) for rr, r in signal_response if isinstance(r, Iterable)])
def create_transactions(self, is_new=False, positions=None, fees=None, dt_now=None, migrated=False,
_backfill_before_cancellation=False, save=True):

View File

@@ -98,10 +98,9 @@ from pretix.base.services.pricing import (
from pretix.base.services.quotas import QuotaAvailability
from pretix.base.services.tasks import ProfiledEventTask, ProfiledTask
from pretix.base.signals import (
allow_ticket_download, order_approved, order_canceled, order_changed,
order_denied, order_expired, order_fee_calculation, order_paid,
order_placed, order_split, order_valid_if_pending, periodic_task,
validate_order,
order_approved, order_canceled, order_changed, order_denied, order_expired,
order_fee_calculation, order_paid, order_placed, order_split,
order_valid_if_pending, periodic_task, validate_order,
)
from pretix.celery_app import app
from pretix.helpers import OF_SELF
@@ -1408,23 +1407,16 @@ def send_download_reminders(sender, **kwargs):
if o.download_reminder_sent:
# Race condition
continue
if not all([r for rr, r in allow_ticket_download.send(event, order=o)]):
positions = o.positions_with_tickets
if not list(positions):
continue
if not o.ticket_download_available:
continue
positions = o.positions.select_related('item')
if o.status != Order.STATUS_PAID:
if o.status != Order.STATUS_PENDING or o.require_approval or (not o.valid_if_pending and not o.event.settings.ticket_download_pending):
continue
send = False
for p in positions:
if p.generate_ticket:
send = True
break
if not send:
continue
with language(o.locale, o.event.settings.region):
o.download_reminder_sent = True
@@ -1442,10 +1434,7 @@ def send_download_reminders(sender, **kwargs):
logger.exception('Reminder email could not be sent')
if event.settings.mail_send_download_reminder_attendee:
for p in o.positions.all():
if not p.generate_ticket:
continue
for p in o.positions_with_tickets:
if p.subevent_id:
reminder_date = (p.subevent.date_from - timedelta(days=days)).replace(
hour=0, minute=0, second=0, microsecond=0

View File

@@ -34,7 +34,7 @@ from pretix.base.models import (
)
from pretix.base.services.tasks import EventTask, ProfiledTask
from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.signals import allow_ticket_download, register_ticket_outputs
from pretix.base.signals import register_ticket_outputs
from pretix.celery_app import app
from pretix.helpers.database import rolledback_transaction
@@ -124,8 +124,8 @@ def preview(event: int, provider: str):
def get_tickets_for_order(order, base_position=None):
can_download = all([r for rr, r in allow_ticket_download.send(order.event, order=order)])
if not can_download:
positions = list(order.positions_with_tickets)
if not positions:
return []
if not order.ticket_download_available:
return []
@@ -135,10 +135,8 @@ def get_tickets_for_order(order, base_position=None):
for receiver, response
in register_ticket_outputs.send(order.event)
]
tickets = []
positions = list(order.positions_with_tickets)
if base_position:
# Only the given position and its children
positions = [
@@ -202,7 +200,6 @@ def get_tickets_for_order(order, base_position=None):
))
except:
logger.exception('Failed to generate ticket.')
return tickets

View File

@@ -646,7 +646,7 @@ allow_ticket_download = EventPluginSignal()
Arguments: ``order``
This signal is sent out to check if tickets for an order can be downloaded. If any receiver returns false,
a download will not be offered.
a download will not be offered. If a receiver returns a list of OrderPositions, only those will be downloadable.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""

View File

@@ -96,6 +96,9 @@ class BaseTicketOutput:
"""
raise NotImplementedError()
def get_tickets_to_print(self, order):
return order.positions_with_tickets
def generate_order(self, order: Order) -> Tuple[str, str, str]:
"""
This method is the same as order() but should not generate one file per order position
@@ -116,7 +119,7 @@ class BaseTicketOutput:
"""
with tempfile.TemporaryDirectory() as d:
with ZipFile(os.path.join(d, 'tmp.zip'), 'w') as zipf:
for pos in order.positions_with_tickets:
for pos in self.get_tickets_to_print(order):
fname, __, content = self.generate(pos)
zipf.writestr('{}-{}{}'.format(
order.code, pos.positionid, os.path.splitext(fname)[1]