Compare commits

..

11 Commits

Author SHA1 Message Date
Richard Schreiber
d4f186fb7c Improve info text (suggestions from code review)
Co-authored-by: luelista <weller@rami.io>
2025-09-01 08:33:15 +02:00
Richard Schreiber
79025e55d6 Fix unhandled not found error when manually managing sync jobs 2025-08-29 10:53:47 +02:00
Richard Schreiber
d23735b1a6 Fix missing payment provider "banktransfer" on export (#5405) 2025-08-26 11:40:24 +02:00
Raphael Michel
d8156186d8 Bump hierarkey to 2.0.1 2025-08-23 09:07:33 +02:00
Raphael Michel
abab7e5bc6 Bank transfer: Do not check for events 2025-08-22 12:47:34 +02:00
Raphael Michel
f89a33862a asynctask.js: Fix gettext being used before translations are loaded (Z#23204825) (#5401) 2025-08-22 10:48:53 +02:00
Raphael Michel
deb7cfa899 Bank transfer: Migrate to a hybrid plugin (#5394)
* Bank transfer: Migrate to a hybrid plugin

* Fix failing tests

* Fix test fixtures

* Add missing fixture
2025-08-22 10:47:52 +02:00
Raphael Michel
3f00fa58a0 Subevents: set inactive if non-batch deletion of subevent fails (Z#23204183) (#5374)
* Subevents: Extend fallback for undeletable dates for single deletion (Z#23204183)

* Fix useless writes

* Update src/pretix/control/views/subevents.py

Co-authored-by: Richard Schreiber <schreiber@rami.io>

* Update src/pretix/control/views/subevents.py

Co-authored-by: Richard Schreiber <schreiber@rami.io>

* Fix flow

---------

Co-authored-by: Richard Schreiber <schreiber@rami.io>
2025-08-22 10:47:47 +02:00
luelista
49c0f6b967 Organizer plugins: Do not show plugins as active if they are inactive on org-level (#5396) 2025-08-22 09:31:01 +02:00
Raphael Michel
fe9a7eaa24 Order overview: Try to make linked filters behave as expected for line-level cancellations (Z#23203500) 2025-08-22 09:30:34 +02:00
Luca Hammer
ebac7d563c Translations: Update German
Currently translated at 100.0% (6068 of 6068 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2025-08-22 09:16:19 +02:00
27 changed files with 194 additions and 102 deletions

View File

@@ -42,7 +42,7 @@ dependencies = [
"django-filter==25.1", "django-filter==25.1",
"django-formset-js-improved==0.5.0.3", "django-formset-js-improved==0.5.0.3",
"django-formtools==2.5.1", "django-formtools==2.5.1",
"django-hierarkey==2.0.*", "django-hierarkey==2.0.*,>=2.0.1",
"django-hijack==3.7.*", "django-hijack==3.7.*",
"django-i18nfield==1.10.*", "django-i18nfield==1.10.*",
"django-libsass==0.9", "django-libsass==0.9",

View File

@@ -197,6 +197,7 @@ def order_overview(
item.all_variations = list(item.variations.all()) item.all_variations = list(item.variations.all())
item.has_variations = (len(item.all_variations) > 0) item.has_variations = (len(item.all_variations) > 0)
item.num = {} item.num = {}
item.subevent = subevent
if item.has_variations: if item.has_variations:
for var in item.all_variations: for var in item.all_variations:
variid = var.id variid = var.id

View File

@@ -107,11 +107,16 @@ def get_all_payment_providers():
return Event return Event
with rolledback_transaction(): with rolledback_transaction():
plugins = ",".join([app.name for app in apps.get_app_configs()])
organizer = Organizer.objects.create(
name="INTERNAL",
plugins=plugins,
)
event = Event.objects.create( event = Event.objects.create(
plugins=",".join([app.name for app in apps.get_app_configs()]), plugins=plugins,
name="INTERNAL", name="INTERNAL",
date_from=now(), date_from=now(),
organizer=Organizer.objects.create(name="INTERNAL") organizer=organizer,
) )
event = FakeEvent(event) event = FakeEvent(event)
provs = register_payment_providers.send( provs = register_payment_providers.send(
@@ -220,6 +225,7 @@ class OrderFilterForm(FilterForm):
(_('Cancellations'), ( (_('Cancellations'), (
(Order.STATUS_CANCELED, _('Canceled (fully)')), (Order.STATUS_CANCELED, _('Canceled (fully)')),
('cp', _('Canceled (fully or with paid fee)')), ('cp', _('Canceled (fully or with paid fee)')),
('cany', _('Canceled (at least one position)')),
('rc', _('Cancellation requested')), ('rc', _('Cancellation requested')),
('cni', _('Fully canceled but invoice not canceled')), ('cni', _('Fully canceled but invoice not canceled')),
)), )),
@@ -396,6 +402,16 @@ class OrderFilterForm(FilterForm):
).filter( ).filter(
Q(status=Order.STATUS_PAID, has_pc=False) | Q(status=Order.STATUS_CANCELED) Q(status=Order.STATUS_PAID, has_pc=False) | Q(status=Order.STATUS_CANCELED)
) )
elif s == 'cany':
s = OrderPosition.all.filter(
order=OuterRef('pk'),
canceled=True,
)
qs = qs.annotate(
has_pc_c=Exists(s)
).filter(
Q(has_pc_c=True) | Q(status=Order.STATUS_CANCELED)
)
if fdata.get('ordering'): if fdata.get('ordering'):
qs = qs.order_by(*get_deterministic_ordering(Order, self.get_order_by())) qs = qs.order_by(*get_deterministic_ordering(Order, self.get_order_by()))
@@ -474,16 +490,31 @@ class EventOrderFilterForm(OrderFilterForm):
fdata = self.cleaned_data fdata = self.cleaned_data
qs = super().filter_qs(qs) qs = super().filter_qs(qs)
# This is a little magic, but there's no option that does not confuse people and let's hope this confuses less
# people.
only_match_noncanceled_products = fdata.get('status') in (
Order.STATUS_PAID,
Order.STATUS_PAID + 'v',
Order.STATUS_PENDING,
Order.STATUS_PENDING + Order.STATUS_PAID,
)
if only_match_noncanceled_products:
canceled_filter = Q(all_positions__canceled=False)
elif fdata.get('status') in ('cp', 'cany'):
canceled_filter = Q(all_positions__canceled=True) | Q(status=Order.STATUS_CANCELED)
else:
canceled_filter = Q()
item = fdata.get('item') item = fdata.get('item')
if item: if item:
if '-' in item: if '-' in item:
var = item.split('-')[1] var = item.split('-')[1]
qs = qs.filter(all_positions__variation_id=var, all_positions__canceled=False).distinct() qs = qs.filter(canceled_filter, all_positions__variation_id=var).distinct()
else: else:
qs = qs.filter(all_positions__item_id=fdata.get('item'), all_positions__canceled=False).distinct() qs = qs.filter(canceled_filter, all_positions__item_id=fdata.get('item')).distinct()
if fdata.get('subevent'): if fdata.get('subevent'):
qs = qs.filter(all_positions__subevent=fdata.get('subevent'), all_positions__canceled=False).distinct() qs = qs.filter(canceled_filter, all_positions__subevent=fdata.get('subevent')).distinct()
if fdata.get('question') and fdata.get('answer') is not None: if fdata.get('question') and fdata.get('answer') is not None:
q = fdata.get('question') q = fdata.get('question')

View File

@@ -74,7 +74,7 @@
<thead> <thead>
<tr> <tr>
<th>{% trans "Product" %}</th> <th>{% trans "Product" %}</th>
<th>{% trans "Canceled" %}¹</th> <th>{% trans "Canceled" %}</th>
<th>{% trans "Expired" %}</th> <th>{% trans "Expired" %}</th>
<th>{% trans "Approval pending" %}</th> <th>{% trans "Approval pending" %}</th>
<th colspan="3" class="text-center">{% trans "Purchased" %}</th> <th colspan="3" class="text-center">{% trans "Purchased" %}</th>
@@ -106,27 +106,27 @@
<tr class="item {% if tup.0 %}categorized{% endif %}"> <tr class="item {% if tup.0 %}categorized{% endif %}">
<td>{{ item }}</td> <td>{{ item }}</td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}&amp;status=c&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}&amp;status=cany&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ item.num.canceled|togglesum:request.event.currency }} {{ item.num.canceled|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}&amp;status=e&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}&amp;status=e&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ item.num.expired|togglesum:request.event.currency }} {{ item.num.expired|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}&amp;status=pa&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}&amp;status=pa&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ item.num.unapproved|togglesum:request.event.currency }} {{ item.num.unapproved|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}&amp;status=na&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}&amp;status=na&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ item.num.pending|togglesum:request.event.currency }} {{ item.num.pending|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}&amp;status=p&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}&amp;status=p&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ item.num.paid|togglesum:request.event.currency }} {{ item.num.paid|togglesum:request.event.currency }}
</a> </a>
</td> </td>
@@ -139,27 +139,27 @@
<tr class="variation {% if tup.0 %}categorized{% endif %}"> <tr class="variation {% if tup.0 %}categorized{% endif %}">
<td>{{ var }}</td> <td>{{ var }}</td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=c&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=cany&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ var.num.canceled|togglesum:request.event.currency }} {{ var.num.canceled|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=e&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=e&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ var.num.expired|togglesum:request.event.currency }} {{ var.num.expired|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=pa&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=pa&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ var.num.unapproved|togglesum:request.event.currency }} {{ var.num.unapproved|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=na&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=na&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ var.num.pending|togglesum:request.event.currency }} {{ var.num.pending|togglesum:request.event.currency }}
</a> </a>
</td> </td>
<td> <td>
<a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=p&amp;provider={{ item.provider }}"> <a href="{{ listurl }}?item={{ item.id }}-{{ var.id }}&amp;status=p&amp;provider={{ item.provider }}{% if subevent %}&amp;subevent={{ subevent.pk }}{% endif %}">
{{ var.num.paid|togglesum:request.event.currency }} {{ var.num.paid|togglesum:request.event.currency }}
</a> </a>
</td> </td>
@@ -185,7 +185,4 @@
</tfoot> </tfoot>
</table> </table>
</div> </div>
<p class="help-block">
¹ {% trans "If you click links in this column, you will only find orders that are canceled completely, while the numbers also include single canceled positions within valid orders." %}
</p>
{% endblock %} {% endblock %}

View File

@@ -69,34 +69,36 @@
{% if show_meta %} {% if show_meta %}
<span class="text-muted text-sm">{{ plugin.version }}</span> <span class="text-muted text-sm">{{ plugin.version }}</span>
{% endif %} {% endif %}
{% if is_active and level == "organizer" %} {% if is_active or plugin.level == "event" %}
<span class="label label-success" data-is-active> {% if plugin.level == "organizer" %}
<span class="fa fa-check" aria-hidden="true"></span> <span class="label label-success" data-is-active>
{% trans "Active" %} <span class="fa fa-check" aria-hidden="true"></span>
</span> {% trans "Active" %}
{% elif events_counter == events_total %} </span>
<span class="label label-success" data-is-active> {% elif events_total and events_counter == events_total %}
<span class="fa fa-check" aria-hidden="true"></span> <span class="label label-success" data-is-active>
{% trans "Active (all events)" %} <span class="fa fa-check" aria-hidden="true"></span>
</span> {% trans "Active (all events)" %}
{% elif events_counter %} </span>
<span class="label label-info" data-is-active> {% elif events_counter %}
<span class="fa fa-check" aria-hidden="true"></span> <span class="label label-info" data-is-active>
{% blocktrans trimmed count count=events_counter %} <span class="fa fa-check" aria-hidden="true"></span>
Active ({{ count }} event) {% blocktrans trimmed count count=events_counter %}
{% plural %} Active ({{ count }} event)
Active ({{ count }} events) {% plural %}
{% endblocktrans %} Active ({{ count }} events)
</span> {% endblocktrans %}
{% elif level == "event_organizer" %} </span>
<span class="label label-info" data-is-active> {% elif level == "event_organizer" %}
<span class="fa fa-check" aria-hidden="true"></span> <span class="label label-info" data-is-active>
{% blocktrans trimmed count count=0 %} <span class="fa fa-check" aria-hidden="true"></span>
Active ({{ count }} event) {% blocktrans trimmed count count=0 %}
{% plural %} Active ({{ count }} event)
Active ({{ count }} events) {% plural %}
{% endblocktrans %} Active ({{ count }} events)
</span> {% endblocktrans %}
</span>
{% endif %}
{% endif %} {% endif %}
</h4> </h4>
{% include "pretixcontrol/event/fragment_plugin_description.html" with plugin=plugin %} {% include "pretixcontrol/event/fragment_plugin_description.html" with plugin=plugin %}

View File

@@ -82,27 +82,35 @@ class ControlSyncJob(OrderView):
messages.success(self.request, _('The sync job has been enqueued and will run in the next minutes.')) messages.success(self.request, _('The sync job has been enqueued and will run in the next minutes.'))
elif self.request.POST.get("cancel_job"): elif self.request.POST.get("cancel_job"):
with transaction.atomic(): with transaction.atomic():
job = self.order.queued_sync_jobs.select_for_update(of=OF_SELF).get( try:
pk=self.request.POST.get("cancel_job") job = self.order.queued_sync_jobs.select_for_update(of=OF_SELF).get(
) pk=self.request.POST.get("cancel_job")
if job.in_flight: )
messages.warning(self.request, _('The sync job is already in progress.')) except OrderSyncQueue.DoesNotExist:
messages.info(self.request, _('The sync job could not be found. It may have been processed in the meantime.'))
else: else:
job.delete() if job.in_flight:
messages.success(self.request, _('The sync job has been canceled.')) messages.warning(self.request, _('The sync job is already in progress.'))
else:
job.delete()
messages.success(self.request, _('The sync job has been canceled.'))
elif self.request.POST.get("run_job_now"): elif self.request.POST.get("run_job_now"):
with transaction.atomic(): with transaction.atomic():
job = self.order.queued_sync_jobs.select_for_update(of=OF_SELF).get( try:
pk=self.request.POST.get("run_job_now") job = self.order.queued_sync_jobs.select_for_update(of=OF_SELF).get(
) pk=self.request.POST.get("run_job_now")
if job.in_flight: )
messages.success(self.request, _('The sync job is already in progress.')) except OrderSyncQueue.DoesNotExist:
messages.info(self.request, _('The sync job could not be found. It may have been processed in the meantime.'))
else: else:
job.not_before = now() if job.in_flight:
job.need_manual_retry = None messages.success(self.request, _('The sync job is already in progress.'))
job.save() else:
sync_single.apply_async(args=(job.pk,)) job.not_before = now()
messages.success(self.request, _('The sync job has been set to run as soon as possible.')) job.need_manual_retry = None
job.save()
sync_single.apply_async(args=(job.pk,))
messages.success(self.request, _('The sync job has been set to run as soon as possible.'))
return redirect(self.get_order_url()) return redirect(self.get_order_url())

View File

@@ -2575,6 +2575,11 @@ class OverView(EventPermissionRequiredMixin, TemplateView):
self.request.event, self.request.event,
fees=True fees=True
) )
ctx['subevent'] = (
self.request.event.has_subevents and
self.filter_form.is_valid() and
self.filter_form.cleaned_data.get('subevent')
)
ctx['subevent_warning'] = ( ctx['subevent_warning'] = (
self.request.event.has_subevents and self.request.event.has_subevents and
self.filter_form.is_valid() and self.filter_form.is_valid() and

View File

@@ -174,21 +174,38 @@ class SubEventDelete(EventPermissionRequiredMixin, CompatDeleteView):
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
@transaction.atomic
def delete(self, request, *args, **kwargs): def delete(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
success_url = self.get_success_url() success_url = self.get_success_url()
if not self.object.allow_delete(): try:
messages.error(request, pgettext_lazy('subevent', 'A date can not be deleted if orders already have been ' with transaction.atomic():
'placed.')) if not self.object.allow_delete():
return HttpResponseRedirect(self.get_success_url()) messages.error(request, pgettext_lazy('subevent', 'A date can not be deleted if orders already have been '
'placed.'))
return HttpResponseRedirect(success_url)
self.object.log_action('pretix.subevent.deleted', user=self.request.user)
CartPosition.objects.filter(addon_to__subevent=self.object).delete()
self.object.cartposition_set.all().delete()
self.object.delete()
except ProtectedError:
if self.object.active:
with transaction.atomic():
self.object.log_action(
'pretix.subevent.changed', user=self.request.user, data={
'active': False
},
)
self.object.active = False
self.object.save(update_fields=['active'])
messages.error(self.request, pgettext_lazy(
'subevent',
'The date could not be deleted as some constraints (e.g. data created by plug-ins) did not allow '
'it. The date was disabled instead.'
))
else: else:
self.object.log_action('pretix.subevent.deleted', user=self.request.user)
CartPosition.objects.filter(addon_to__subevent=self.object).delete()
self.object.cartposition_set.all().delete()
self.object.delete()
messages.success(request, pgettext_lazy('subevent', 'The selected date has been deleted.')) messages.success(request, pgettext_lazy('subevent', 'The selected date has been deleted.'))
return HttpResponseRedirect(success_url) return HttpResponseRedirect(success_url)
def get_success_url(self) -> str: def get_success_url(self) -> str:

View File

@@ -5,8 +5,8 @@ msgstr ""
"Project-Id-Version: 1\n" "Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-08-19 16:35+0000\n" "POT-Creation-Date: 2025-08-19 16:35+0000\n"
"PO-Revision-Date: 2025-08-19 17:11+0000\n" "PO-Revision-Date: 2025-08-21 21:00+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n" "Last-Translator: Luca Hammer <hammer@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/" "Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/"
">\n" ">\n"
"Language: de\n" "Language: de\n"
@@ -34943,7 +34943,7 @@ msgstr "Ihre Bestellung war erfolgreich! Sie finden weiter unten alle Details."
#: pretix/presale/templates/pretixpresale/event/order.html:19 #: pretix/presale/templates/pretixpresale/event/order.html:19
#: pretix/presale/templates/pretixpresale/event/order.html:50 #: pretix/presale/templates/pretixpresale/event/order.html:50
msgid "We successfully received your payment. See below for details." msgid "We successfully received your payment. See below for details."
msgstr "Wir haben Ihre Zahlung erfolgreich erhalten." msgstr "Wir haben Ihre Zahlung erfolgreich erhalten. Details siehe unten."
#: pretix/presale/templates/pretixpresale/event/order.html:35 #: pretix/presale/templates/pretixpresale/event/order.html:35
msgid "" msgid ""

View File

@@ -24,6 +24,7 @@ from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from pretix import __version__ as version from pretix import __version__ as version
from pretix.base.plugins import PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID
class BankTransferApp(AppConfig): class BankTransferApp(AppConfig):
@@ -45,6 +46,7 @@ class BankTransferApp(AppConfig):
((_("Bank transfer"), _("Import bank data")), "plugins:banktransfer:import", {}), ((_("Bank transfer"), _("Import bank data")), "plugins:banktransfer:import", {}),
((_("Bank transfer"), _("Export refunds")), "plugins:banktransfer:refunds.list", {}), ((_("Bank transfer"), _("Export refunds")), "plugins:banktransfer:refunds.list", {}),
] ]
level = PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID
def ready(self): def ready(self):
from . import signals # NOQA from . import signals # NOQA

View File

@@ -0,0 +1,30 @@
# Generated by Django 4.2.16 on 2025-08-20 11:35
from django.db import migrations
from django.db.models import Exists, OuterRef
def activate_plugin(apps, schema_editor):
Event = apps.get_model('pretixbase', 'Event')
Organizer = apps.get_model('pretixbase', 'Organizer')
qs = Organizer.objects.filter(
Exists(Event.objects.filter(organizer_id=OuterRef("pk"), plugins__contains="pretix.plugins.banktransfer"))
)
for org in qs:
if "pretix.plugins.banktransfer" not in org.plugins:
org.plugins = ",".join(org.plugins.split(",") + ["pretix.plugins.banktransfer"])
org.save(update_fields=["plugins"])
class Migration(migrations.Migration):
dependencies = [
("banktransfer", "0011_banktransaction_external_id"),
("pretixbase", "0287_organizer_plugins"),
]
operations = [
migrations.RunPython(
activate_plugin,
migrations.RunPython.noop,
)
]

View File

@@ -78,8 +78,6 @@ def control_nav_orga_import(sender, request=None, **kwargs):
url = resolve(request.path_info) url = resolve(request.path_info)
if not request.user.has_organizer_permission(request.organizer, 'can_change_orders', request=request): if not request.user.has_organizer_permission(request.organizer, 'can_change_orders', request=request):
return [] return []
if not request.organizer.events.filter(plugins__icontains='pretix.plugins.banktransfer'):
return []
return [ return [
{ {
'label': _("Bank transfer"), 'label': _("Bank transfer"),

View File

@@ -8,15 +8,16 @@ var async_task_is_long = false;
var async_task_dont_redirect = false; var async_task_dont_redirect = false;
var async_task_status_messages = { var async_task_status_messages = {
long_task_started: gettext( // These are functions in order to be lazily evaluated after the gettext file is loaded
long_task_started: () => gettext(
'Your request is currently being processed. Depending on the size of your event, this might take up to ' + 'Your request is currently being processed. Depending on the size of your event, this might take up to ' +
'a few minutes.' 'a few minutes.'
), ),
long_task_pending: gettext( long_task_pending: () => gettext(
'Your request has been queued on the server and will soon be ' + 'Your request has been queued on the server and will soon be ' +
'processed.' 'processed.'
), ),
short_task: gettext( short_task: () => gettext(
'Your request arrived on the server but we still wait for it to be ' + 'Your request arrived on the server but we still wait for it to be ' +
'processed. If this takes longer than two minutes, please contact us or go ' + 'processed. If this takes longer than two minutes, please contact us or go ' +
'back in your browser and try again.' 'back in your browser and try again.'
@@ -73,12 +74,12 @@ function async_task_check_callback(data, textStatus, jqXHR) {
function async_task_update_status(data) { function async_task_update_status(data) {
if (async_task_is_long) { if (async_task_is_long) {
if (data.started) { if (data.started) {
waitingDialog.setStatus(async_task_status_messages.long_task_started); waitingDialog.setStatus(async_task_status_messages.long_task_started());
} else { } else {
waitingDialog.setStatus(async_task_status_messages.long_task_pending); waitingDialog.setStatus(async_task_status_messages.long_task_pending());
} }
} else { } else {
waitingDialog.setStatus(async_task_status_messages.short_task); waitingDialog.setStatus(async_task_status_messages.short_task());
} }
} }

View File

@@ -52,7 +52,7 @@ def client():
@pytest.fixture @pytest.fixture
@scopes_disabled() @scopes_disabled()
def organizer(): def organizer():
return Organizer.objects.create(name='Dummy', slug='dummy') return Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
@pytest.fixture @pytest.fixture

View File

@@ -31,7 +31,7 @@ TEST_ORGANIZER_RES = {
"name": "Dummy", "name": "Dummy",
"slug": "dummy", "slug": "dummy",
"public_url": "http://example.com/dummy/", "public_url": "http://example.com/dummy/",
"plugins": [], "plugins": ["pretix.plugins.banktransfer"],
} }

View File

@@ -47,7 +47,7 @@ TZ = ZoneInfo('Europe/Berlin')
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def event(): def event():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
o.settings.customer_accounts = True o.settings.customer_accounts = True
event = Event.objects.create( event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',

View File

@@ -64,7 +64,7 @@ from pretix.testutils.scope import classscope
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def event(): def event():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
event = Event.objects.create( event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now(), date_from=now(),
@@ -1441,7 +1441,7 @@ class OrderCancelTests(TestCase):
class OrderChangeManagerTests(TestCase): class OrderChangeManagerTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.o = Organizer.objects.create(name='Dummy', slug='dummy') self.o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
with scope(organizer=self.o): with scope(organizer=self.o):
self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(), self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(),
plugins='pretix.plugins.banktransfer') plugins='pretix.plugins.banktransfer')

View File

@@ -45,7 +45,7 @@ from pretix.base.shredder import (
@pytest.fixture @pytest.fixture
def event(): def event():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
event = Event.objects.create( event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf' date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf'

View File

@@ -45,7 +45,7 @@ def autoskip(request, settings):
@pytest.fixture @pytest.fixture
@scopes_disabled() @scopes_disabled()
def organizer(): def organizer():
return Organizer.objects.create(name='Dummy', slug='dummy') return Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
@pytest.fixture @pytest.fixture

View File

@@ -60,8 +60,8 @@ class EventsTest(SoupTest):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc') self.orga1 = Organizer.objects.create(name='CCC', slug='ccc', plugins='pretix.plugins.banktransfer')
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm') self.orga2 = Organizer.objects.create(name='MRM', slug='mrm', plugins='pretix.plugins.banktransfer')
self.event1 = Event.objects.create( self.event1 = Event.objects.create(
organizer=self.orga1, name='30C3', slug='30c3', organizer=self.orga1, name='30C3', slug='30c3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),

View File

@@ -60,7 +60,7 @@ from pretix.base.services.tax import VATIDFinalError, VATIDTemporaryError
@pytest.fixture @pytest.fixture
def env(): def env():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
event = Event.objects.create( event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy' date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy'

View File

@@ -49,7 +49,7 @@ from pretix.base.models import (
@pytest.fixture @pytest.fixture
def env(): def env():
o = Organizer.objects.create(name='Dummy', slug='dummy') o = Organizer.objects.create(name='Dummy', slug='dummy', plugins='pretix.plugins.banktransfer')
event = Event.objects.create( event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy', organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy' date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy'

View File

@@ -43,8 +43,8 @@ class OrganizerTest(SoupTest):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc') self.orga1 = Organizer.objects.create(name='CCC', slug='ccc', plugins='pretix.plugins.banktransfer')
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm') self.orga2 = Organizer.objects.create(name='MRM', slug='mrm', plugins='pretix.plugins.banktransfer')
self.event1 = Event.objects.create( self.event1 = Event.objects.create(
organizer=self.orga1, name='30C3', slug='30c3', organizer=self.orga1, name='30C3', slug='30c3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),

View File

@@ -31,7 +31,7 @@ from pretix.base.models import Event, Organizer, Team
@pytest.fixture @pytest.fixture
@scopes_disabled() @scopes_disabled()
def organizer(): def organizer():
return Organizer.objects.create(name="Dummy", slug="dummy") return Organizer.objects.create(name="Dummy", slug="dummy", plugins='pretix.plugins.banktransfer')
@pytest.fixture @pytest.fixture

View File

@@ -70,7 +70,7 @@ class BaseCheckoutTestCase:
@scopes_disabled() @scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.orga = Organizer.objects.create(name='CCC', slug='ccc') self.orga = Organizer.objects.create(name='CCC', slug='ccc', plugins='pretix.plugins.banktransfer')
self.event = Event.objects.create( self.event = Event.objects.create(
organizer=self.orga, name='30C3', slug='30c3', organizer=self.orga, name='30C3', slug='30c3',
date_from=datetime.datetime(now().year + 1, 12, 26, tzinfo=datetime.timezone.utc), date_from=datetime.datetime(now().year + 1, 12, 26, tzinfo=datetime.timezone.utc),

View File

@@ -55,7 +55,7 @@ class BaseOrdersTest(TestCase):
@scopes_disabled() @scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.orga = Organizer.objects.create(name='CCC', slug='ccc') self.orga = Organizer.objects.create(name='CCC', slug='ccc', plugins='pretix.plugins.banktransfer')
self.event = Event.objects.create( self.event = Event.objects.create(
organizer=self.orga, name='30C3', slug='30c3', organizer=self.orga, name='30C3', slug='30c3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),

View File

@@ -56,7 +56,7 @@ class BaseOrdersTest(TestCase):
@scopes_disabled() @scopes_disabled()
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.orga = Organizer.objects.create(name='CCC', slug='ccc') self.orga = Organizer.objects.create(name='CCC', slug='ccc', plugins='pretix.plugins.banktransfer')
self.event = Event.objects.create( self.event = Event.objects.create(
organizer=self.orga, name='30C3', slug='30c3', organizer=self.orga, name='30C3', slug='30c3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),