forked from CGM_Public/pretix_original
Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1226de8d2f | |||
| c0d7630eae | |||
| 8fe136b374 | |||
| f055a598ce | |||
| 9138464896 | |||
| 479f51a84c | |||
| a3ac54d419 | |||
| b2841e5c61 | |||
| 3009f50d51 | |||
| ff3a49ab2a | |||
| 19f3fbc7e8 | |||
| bb9b9ac9aa | |||
| d7f6befb5b | |||
| 2287be2009 | |||
| 0480b6873d | |||
| 711f08c9e8 | |||
| d18914fcca | |||
| 2411144262 | |||
| 2f02d35a52 | |||
| 71e82fda81 | |||
| ca3802da90 | |||
| 2c68b9e895 | |||
| 01092498f4 | |||
| fd841ed66d | |||
| 04cbccb536 | |||
| b8ea93de1e | |||
| c49f42301c | |||
| 2ae0a16e67 | |||
| 6b06fdf822 | |||
| ea3f4e5f62 | |||
| d71c23f7e0 | |||
| 5ed7b0032b | |||
| a77f2d01a7 | |||
| ca4f511cde | |||
| 83b1c2ea7e | |||
| c91eb2e20d | |||
| bfb480a288 | |||
| 22e2143623 | |||
| 9e61f7f978 | |||
| 092de9e3c4 | |||
| f0822d3c27 | |||
| 6fc47ca3b6 | |||
| 3716a686f5 | |||
| 9c0c77958e | |||
| 6154a44274 | |||
| d5aff10297 | |||
| 846e39a652 | |||
| 75d37b2a37 | |||
| 2a0c3da8c4 | |||
| fb7f4d1160 | |||
| 5c8817f0c3 | |||
| 7663bf7994 | |||
| ea8f74f8aa | |||
| 7b34701449 | |||
| 06f4bfea24 | |||
| e2862a98a0 | |||
| 82f4feadc3 | |||
| 906222c7d3 | |||
| 7ce2089ca8 | |||
| 2133584ed2 | |||
| c3c50d7205 | |||
| 4f7a41a4b2 | |||
| 93fd79ab33 | |||
| 59595c2f10 | |||
| 91c6d09f0b | |||
| 570a818129 | |||
| d63e2ebe2d | |||
| 884c97d62a | |||
| 032e958a00 | |||
| 7b16dfefbc | |||
| 8a5b13dee9 | |||
| d7dde8c23e | |||
| 1e2f93fbc5 | |||
| 493fc03686 | |||
| 8d6d885f6e | |||
| 2aa989c293 | |||
| 06b226f40f | |||
| 73038b0d97 | |||
| 4513e31f0d | |||
| d34175114b | |||
| b2c71b47ce | |||
| a889abc52b | |||
| 8c01b2a469 | |||
| 720c7fd7bb | |||
| 6ae6eba4de | |||
| a173e347ea | |||
| 94d13e4cdd | |||
| e618441231 | |||
| cd57f1f024 | |||
| 075b9c187f | |||
| d9f46cb817 | |||
| 2892d16861 | |||
| 9128624d68 | |||
| d2cf8f801d | |||
| 682d0f886d | |||
| d2cbd41a19 | |||
| 828f4e3168 |
@@ -5,7 +5,6 @@ on:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- 'src/pretix/locale/**'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
|
||||
@@ -65,7 +65,7 @@ Package dependencies
|
||||
To build and run pretix, you will need the following debian packages::
|
||||
|
||||
# apt-get install git build-essential python3-dev python3-venv python3 python3-pip \
|
||||
python3-dev libxml2-dev libxslt1-dev libffi-dev zlib1g-dev libssl-dev \
|
||||
libxml2-dev libxslt1-dev libffi-dev zlib1g-dev libssl-dev \
|
||||
gettext libpq-dev libjpeg-dev libopenjp2-7-dev
|
||||
|
||||
Config file
|
||||
|
||||
@@ -40,6 +40,11 @@ answers list of objects Answers to user
|
||||
seat objects The assigned seat (or ``null``)
|
||||
├ id integer Internal ID of the seat instance
|
||||
├ name string Human-readable seat name
|
||||
├ zone_name string Name of the zone the seat is in
|
||||
├ row_name string Name/number of the row the seat is in
|
||||
├ row_label string Additional label of the row (or ``null``)
|
||||
├ seat_number string Number of the seat within the row
|
||||
├ seat_label string Additional label of the seat (or ``null``)
|
||||
└ seat_guid string Identifier of the seat within the seating plan
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ Endpoints
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string secret: Only show gift cards with the given secret.
|
||||
:query string value: Only show gift cards with the given value.
|
||||
:query boolean expired: Filter for gift cards that are (not) expired.
|
||||
:query boolean testmode: Filter for gift cards that are (not) in test mode.
|
||||
:query boolean include_accepted: Also show gift cards issued by other organizers that are accepted by this organizer.
|
||||
:query string expand: If you pass ``"owner_ticket"``, the respective field will be shown as a nested value instead of just an ID.
|
||||
|
||||
@@ -164,6 +164,7 @@ Endpoints
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string search: Filter the list by the value of the variation (substring search).
|
||||
:query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be
|
||||
returned.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
|
||||
@@ -392,6 +392,7 @@ Endpoints
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string search: Filter the list by internal name or name of the item (substring search).
|
||||
:query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be
|
||||
returned.
|
||||
:query integer category: If set to the ID of a category, only items within that category will be returned.
|
||||
|
||||
@@ -42,6 +42,8 @@ payment_date date **DEPRECATED AN
|
||||
payment_provider string **DEPRECATED AND INACCURATE** Payment provider used for this order
|
||||
total money (string) Total value of this order
|
||||
comment string Internal comment on this order
|
||||
api_meta object Meta data for that order. Only available through API, no guarantees
|
||||
on the content structure. You can use this to save references to your system.
|
||||
custom_followup_at date Internal date for a custom follow-up action
|
||||
checkin_attention boolean If ``true``, the check-in app should show a warning
|
||||
that this ticket requires special attention if a ticket
|
||||
@@ -215,6 +217,11 @@ answers list of objects Answers to user
|
||||
seat objects The assigned seat. Can be ``null``.
|
||||
├ id integer Internal ID of the seat instance
|
||||
├ name string Human-readable seat name
|
||||
├ zone_name string Name of the zone the seat is in
|
||||
├ row_name string Name/number of the row the seat is in
|
||||
├ row_label string Additional label of the row (or ``null``)
|
||||
├ seat_number string Number of the seat within the row
|
||||
├ seat_label string Additional label of the seat (or ``null``)
|
||||
└ seat_guid string Identifier of the seat within the seating plan
|
||||
pdf_data object Data object required for ticket PDF generation. By default,
|
||||
this field is missing. It will be added only if you add the
|
||||
@@ -455,10 +462,13 @@ List of all orders
|
||||
:query datetime modified_since: Only return orders that have changed since the given date. Be careful: We only
|
||||
recommend using this in combination with ``testmode=false``, since test mode orders can vanish at any time and
|
||||
you will not notice it using this method.
|
||||
:query datetime created_since: Only return orders that have been created since the given date.
|
||||
:query datetime created_since: Only return orders that have been created since the given date (inclusive).
|
||||
:query datetime created_before: Only return orders that have been created before the given date (exclusive).
|
||||
:query integer subevent: Only return orders with a position that contains this subevent ID. *Warning:* Result will also include orders if they contain mixed subevents, and it will even return orders where the subevent is only contained in a canceled position.
|
||||
:query datetime subevent_after: Only return orders that contain a ticket for a subevent taking place after the given date. This is an exclusive after, and it considers the **end** of the subevent (or its start, if the end is not set).
|
||||
:query datetime subevent_before: Only return orders that contain a ticket for a subevent taking place after the given date. This is an exclusive before, and it considers the **start** of the subevent.
|
||||
:query string sales_channel: Only return orders with the given sales channel identifier (e.g. ``"web"``).
|
||||
:query string payment_provider: Only return orders that contain a payment using the given payment provider. Note that this also searches for partial incomplete, or failed payments within the order and is not useful to get a sum of payment amounts without further processing.
|
||||
:query string exclude: Exclude a field from the output, e.g. ``fees`` or ``positions.downloads``. Can be used as a performance optimization. Can be passed multiple times.
|
||||
:query string include: Include only the given field in the output, e.g. ``fees`` or ``positions.downloads``. Can be used as a performance optimization. Can be passed multiple times. ``include`` is applied before ``exclude``, so ``exclude`` takes precedence.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -554,6 +564,7 @@ Fetching individual orders
|
||||
"fees": [],
|
||||
"total": "23.00",
|
||||
"comment": "",
|
||||
"api_meta": {},
|
||||
"custom_followup_at": null,
|
||||
"checkin_attention": false,
|
||||
"checkin_text": null,
|
||||
@@ -734,6 +745,8 @@ Updating order fields
|
||||
|
||||
* ``comment``
|
||||
|
||||
* ``api_meta``
|
||||
|
||||
* ``custom_followup_at``
|
||||
|
||||
* ``invoice_address`` (you always need to supply the full object, or ``null`` to delete the current address)
|
||||
|
||||
@@ -41,6 +41,7 @@ The following values for ``action_types`` are valid with pretix core:
|
||||
* ``pretix.event.order.modified``
|
||||
* ``pretix.event.order.contact.changed``
|
||||
* ``pretix.event.order.changed.*``
|
||||
* ``pretix.event.order.deleted`` (can only occur for test mode orders)
|
||||
* ``pretix.event.order.refund.created``
|
||||
* ``pretix.event.order.refund.created.externally``
|
||||
* ``pretix.event.order.refund.requested``
|
||||
@@ -115,6 +116,7 @@ Endpoints
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean enabled: Only show webhooks that are or are not enabled
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
|
||||
@@ -35,11 +35,11 @@ Frontend
|
||||
--------
|
||||
|
||||
.. automodule:: pretix.presale.signals
|
||||
:members: html_head, html_footer, footer_link, global_footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header
|
||||
:members: html_head, html_footer, footer_link, global_footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header, seatingframe_html_head
|
||||
|
||||
|
||||
.. automodule:: pretix.presale.signals
|
||||
:members: order_info, order_info_top, order_meta_from_request
|
||||
:members: order_info, order_info_top, order_meta_from_request, order_api_meta_from_request
|
||||
|
||||
Request flow
|
||||
""""""""""""
|
||||
|
||||
@@ -17,7 +17,7 @@ The project pretix is split into several components. The main components are:
|
||||
create and manage their events, items, orders and tickets.
|
||||
|
||||
**presale**
|
||||
This is the ticket-shop itself, containing all of the parts visible to the
|
||||
This is the ticket shop itself, containing all of the parts visible to the
|
||||
end user. Also called "frontend" in parts of this documentation.
|
||||
|
||||
**api**
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
GetYourGuide
|
||||
============
|
||||
|
||||
.. note::
|
||||
|
||||
The GetYourGuide integration is currently in Beta. Please contact support@pretix.eu to enable the integration
|
||||
for your pretix.eu organizer account.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
Using third party aggregators, such als GetYourGuide, event organizers can sell tickets to their events not only on
|
||||
their own ticket-shop but also on the aggregator's portal. While this service is not for free, it allows event
|
||||
organizers to reacher a larger audience that would otherwise not have found their way into the organizers webshop.
|
||||
|
||||
Using pretix' integration with GetYourGuide, event organizers can profit from an additional sales and revenue channel,
|
||||
while keeping the effort for setting up and maintaining multiple ticket shops to a minimum.
|
||||
|
||||
Preparing your organizer account
|
||||
--------------------------------
|
||||
The first step in enabling the GetYourGuide integration, is to setup a corresponding Sales Channel, which will be used
|
||||
to properly attribute the sales generated. This needs to be done only once per organizer account.
|
||||
|
||||
To do so, log into the pretix backend, select ``Organizers`` from the navigation and then the organizer in question.
|
||||
Extending the ``Settings``-menu, find the ``Sales channels`` configuration and click the ``Add a new channel`` button.
|
||||
|
||||
On the following page, you will be able to select ``GetYourGuide`` as the sales channel type and give it a custom name.
|
||||
|
||||
Preparing your event
|
||||
--------------------
|
||||
In order to now sell your events on GetYourGuide, you will need to configure each event in question.
|
||||
|
||||
1. Enabling the plugin
|
||||
Within your event, extend the ``Settings`` menu and navigate to ``Plugins``. Activate the plugin in the
|
||||
``Integrations`` tab.
|
||||
|
||||
2. Sell the event on the sales channel
|
||||
Pick the sales channel or channels, on which you would like to sell your event by navigating to the event's general
|
||||
settings page using the ``Sell on all sales channels`` or ``Restrict to specific sales channels`` checkboxes.
|
||||
|
||||
3. Configure one or more products to be sold on GetYourGuide
|
||||
Either create a new or edit an existing product, that you would like to sell on GetYourGuide. To do so, you will
|
||||
need to have checked the ``Sell on all sales channels`` or appropriate ``Restrict to specific sales channels``
|
||||
checkbox of the product within it's ``Availability`` tab.
|
||||
In addition, you will also need to set the GetYourGuide equivalent ticket category in the product's accordingly
|
||||
named settings tab. Within your event, there can be only one product per ticket category. Depending on your further
|
||||
configuration, you must at least select one product to be in the ``Adult`` or ``Group`` category.
|
||||
|
||||
4. Configuring the GetYourGuide-plugin
|
||||
Once you have configured one or more products to be eligible to be sold on GetYourGuide, you'll need to configure a
|
||||
few basic settings within the event (``Settings`` --> ``GetYourGuide``). The most important settings can be found
|
||||
the in the ``Configuration`` tab, such as the location of the event on sale.
|
||||
|
||||
Ticket Categories
|
||||
-----------------
|
||||
While pretix only uses the ticket category term loosely to group together multiple products for nicer display,
|
||||
GetYourGuide is relying on the ticket categories to price the tickets.
|
||||
|
||||
First of all, you need to make the decision on how you are planning on selling your tickets on GetYourGuide - in most
|
||||
cases, this will reflect your current sales strategy within your pretix shop.
|
||||
|
||||
- Individual tickets
|
||||
Every single person attending will need to purchase their own ticket. A family of two adults and two
|
||||
children will have to purchase and pay for a total of 4 tickets.
|
||||
In this case, you will need to offer *at least* a ticket of the ``Adult`` type, but may offer any other ticket
|
||||
category type (Child, Youth, Senior, ...) in addition. But you cannot offer a ``Group`` ticket.
|
||||
|
||||
- Group tickets
|
||||
Two groups, consisting of 10 and 20 participants respectively, won't need to purchase a total of 30 tickets, but
|
||||
rather two group tickets. It is up to you to configure the group size limits within the GetYourGuide-settings of your
|
||||
product.
|
||||
Choosing this option, you cannot offer any other ticket categories besides ``Group``.
|
||||
|
||||
Setting up event dates and quotas
|
||||
---------------------------------
|
||||
Of course, in addition to creating products, you will also need to add them to a quota for them to be available for
|
||||
sale. The process for doing this is the very same as for any regular event or event series.
|
||||
|
||||
.. note::
|
||||
|
||||
When selling individual tickets through GetYourGuide, you will not be able to offer differing quantities for
|
||||
individual ticket categories.
|
||||
|
||||
For this reason, we recommend to place all GetYourGuide-eligible products into the same quota. Should you however opt
|
||||
to create multiple quotas which create an imbalance, pretix will report only the available number of tickets for the
|
||||
lowest relevant quota.
|
||||
|
||||
Connecting your event to GetYourGuide
|
||||
-------------------------------------
|
||||
Once you have set up your event and products and performed all necessary configuration, you may want to use the
|
||||
Analyzer-feature of our GetYourGuide-plugin (``Settings`` -> ``GetYourGuide`` -> tab ``Analyzer``).
|
||||
|
||||
The Analyzer should not display any blocking error messages and at least one event date that is ready for publishing on
|
||||
the GetYourGuide platform.
|
||||
|
||||
At this point, you will need to setup your event (called ``product`` in the GetYourGuide universe) on their
|
||||
`Supplier Portal`_ and connect it with your pretix shop. To do so, please follow the
|
||||
`Connecting a new product to your Reservation System`_ on the GetYourGuide Supply Partner Help Center.
|
||||
|
||||
Select ``pretix.eu`` as your reservation system; the required ``product ID`` can be found in the ``Configuration`` tab
|
||||
of the GetYourGuide plugin settings page.
|
||||
|
||||
From this point on, GetYourGuide will automatically import the availabilities and products and offer them for sale.
|
||||
|
||||
.. _Supplier Portal: https://suppliers.getyourguide.com/
|
||||
.. _Connecting a new product to your Reservation System: https://supply.getyourguide.support/hc/en-us/articles/18008029689373-Connecting-a-new-product-to-your-Reservation-system
|
||||
@@ -25,3 +25,4 @@ If you want to **create** a plugin, please go to the
|
||||
webinar
|
||||
presale-saml
|
||||
kulturpass
|
||||
getyourguide
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
sphinx==7.3.*
|
||||
sphinx==7.4.*
|
||||
jinja2==3.1.*
|
||||
sphinx-rtd-theme
|
||||
sphinxcontrib-httpdomain
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-e ../
|
||||
sphinx==7.3.*
|
||||
sphinx==7.4.*
|
||||
jinja2==3.1.*
|
||||
sphinx-rtd-theme
|
||||
sphinxcontrib-httpdomain
|
||||
|
||||
@@ -449,6 +449,16 @@ Further reading:
|
||||
|
||||
* `Stripe Payment Method Domain registration`_
|
||||
|
||||
|
||||
External payment providers and Cross-Origin-Opener-Policy
|
||||
---------------------------------------------------------
|
||||
|
||||
If you use a payment provider that opens a new window during checkout (such as PayPal), be aware that setting
|
||||
``Cross-Origin-Opener-Policy: same-origin`` results in an empty popup-window being opened in the foreground. This is
|
||||
due to JavaScript not having access to the opened window. To mitigate this, you either need to always open the widget’s
|
||||
checkout in a new tab (see :ref:`Always open a new tab`) or set ``Cross-Origin-Opener-Policy: same-origin-allow-popups``
|
||||
|
||||
|
||||
Working with Cross-Origin-Embedder-Policy
|
||||
-----------------------------------------
|
||||
|
||||
|
||||
+7
-7
@@ -38,13 +38,13 @@ dependencies = [
|
||||
"dj-static",
|
||||
"Django[argon2]==4.2.*",
|
||||
"django-bootstrap3==24.2",
|
||||
"django-compressor==4.5",
|
||||
"django-compressor==4.5.1",
|
||||
"django-countries==7.6.*",
|
||||
"django-filter==24.2",
|
||||
"django-formset-js-improved==0.5.0.3",
|
||||
"django-formtools==2.5.1",
|
||||
"django-hierarkey==1.2.*",
|
||||
"django-hijack==3.5.*",
|
||||
"django-hijack==3.6.*",
|
||||
"django-i18nfield==1.9.*,>=1.9.4",
|
||||
"django-libsass==0.9",
|
||||
"django-localflavor==4.0",
|
||||
@@ -75,15 +75,15 @@ dependencies = [
|
||||
"paypal-checkout-serversdk==1.0.*",
|
||||
"PyJWT==2.8.*",
|
||||
"phonenumberslite==8.13.*",
|
||||
"Pillow==10.3.*",
|
||||
"Pillow==10.4.*",
|
||||
"pretix-plugin-build",
|
||||
"protobuf==5.27.*",
|
||||
"psycopg2-binary",
|
||||
"pycountry",
|
||||
"pycparser==2.22",
|
||||
"pycryptodome==3.20.*",
|
||||
"pypdf==4.2.*",
|
||||
"python-bidi==0.4.*", # Support for Arabic in reportlab
|
||||
"pypdf==4.3.*",
|
||||
"python-bidi==0.5.*", # Support for Arabic in reportlab
|
||||
"python-dateutil==2.9.*",
|
||||
"pytz",
|
||||
"pytz-deprecation-shim==0.1.*",
|
||||
@@ -92,7 +92,7 @@ dependencies = [
|
||||
"redis==5.0.*",
|
||||
"reportlab==4.2.*",
|
||||
"requests==2.31.*",
|
||||
"sentry-sdk==2.5.*",
|
||||
"sentry-sdk==2.10.*",
|
||||
"sepaxml==2.6.*",
|
||||
"slimit",
|
||||
"static3==0.7.*",
|
||||
@@ -127,7 +127,7 @@ dev = [
|
||||
"pytest-rerunfailures==14.*",
|
||||
"pytest-sugar",
|
||||
"pytest-xdist==3.6.*",
|
||||
"pytest==8.2.*",
|
||||
"pytest==8.3.*",
|
||||
"responses",
|
||||
]
|
||||
|
||||
|
||||
@@ -21,8 +21,9 @@
|
||||
#
|
||||
import json
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import prefetch_related_objects
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
|
||||
class AsymmetricField(serializers.Field):
|
||||
@@ -80,6 +81,7 @@ class SalesChannelMigrationMixin:
|
||||
|
||||
def to_internal_value(self, data):
|
||||
if "sales_channels" in data:
|
||||
prefetch_related_objects([self.organizer], "sales_channels")
|
||||
all_channels = {
|
||||
s.identifier for s in
|
||||
self.organizer.sales_channels.all()
|
||||
@@ -109,6 +111,7 @@ class SalesChannelMigrationMixin:
|
||||
def to_representation(self, value):
|
||||
value = super().to_representation(value)
|
||||
if value.get("all_sales_channels"):
|
||||
prefetch_related_objects([self.organizer], "sales_channels")
|
||||
value["sales_channels"] = sorted([
|
||||
s.identifier for s in
|
||||
self.organizer.sales_channels.all()
|
||||
|
||||
@@ -281,13 +281,17 @@ class EventSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
|
||||
from pretix.base.plugins import get_all_plugins
|
||||
|
||||
plugins_available = {
|
||||
p.module for p in get_all_plugins(self.instance)
|
||||
p.module: p for p in get_all_plugins(self.instance)
|
||||
if not p.name.startswith('.') and getattr(p, 'visible', True)
|
||||
}
|
||||
settings_holder = self.instance if self.instance and self.instance.pk else self.context['organizer']
|
||||
|
||||
for plugin in value.get('plugins'):
|
||||
if plugin not in plugins_available:
|
||||
raise ValidationError(_('Unknown plugin: \'{name}\'.').format(name=plugin))
|
||||
if getattr(plugins_available[plugin], 'restricted', False):
|
||||
if plugin not in settings_holder.settings.allowed_restricted_plugins:
|
||||
raise ValidationError(_('Restricted plugin: \'{name}\'.').format(name=plugin))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -76,7 +76,9 @@ class InlineItemVariationSerializer(SalesChannelMigrationMixin, I18nAwareModelSe
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['require_membership_types'].queryset = lazy(lambda: self.context['event'].organizer.membership_types.all(), QuerySet)
|
||||
self.fields['limit_sales_channels'].child_relation.queryset = lazy(lambda: self.context['event'].organizer.sales_channels.all(), QuerySet)
|
||||
self.fields['limit_sales_channels'].child_relation.queryset = (
|
||||
self.context['event'].organizer.sales_channels.all() if 'event' in self.context else SalesChannel.objects.none()
|
||||
)
|
||||
|
||||
def validate_meta_data(self, value):
|
||||
for key in value['meta_data'].keys():
|
||||
@@ -115,11 +117,15 @@ class ItemVariationSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializ
|
||||
def create(self, validated_data):
|
||||
meta_data = validated_data.pop('meta_data', None)
|
||||
require_membership_types = validated_data.pop('require_membership_types', [])
|
||||
limit_sales_channels = validated_data.pop('limit_sales_channels', [])
|
||||
variation = ItemVariation.objects.create(**validated_data)
|
||||
|
||||
if require_membership_types:
|
||||
variation.require_membership_types.add(*require_membership_types)
|
||||
|
||||
if limit_sales_channels:
|
||||
variation.limit_sales_channels.add(*limit_sales_channels)
|
||||
|
||||
# Meta data
|
||||
if meta_data is not None:
|
||||
for key, value in meta_data.items():
|
||||
@@ -284,6 +290,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
|
||||
self.fields['require_membership_types'].queryset = self.context['event'].organizer.membership_types.all()
|
||||
self.fields['grant_membership_type'].queryset = self.context['event'].organizer.membership_types.all()
|
||||
self.fields['limit_sales_channels'].child_relation.queryset = self.context['event'].organizer.sales_channels.all()
|
||||
self.fields['variations'].child.fields['limit_sales_channels'].child_relation.queryset = self.context['event'].organizer.sales_channels.all()
|
||||
|
||||
def validate(self, data):
|
||||
data = super().validate(data)
|
||||
@@ -371,10 +378,13 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
|
||||
|
||||
for variation_data in variations_data:
|
||||
require_membership_types = variation_data.pop('require_membership_types', [])
|
||||
limit_sales_channels = variation_data.pop('limit_sales_channels', [])
|
||||
var_meta_data = variation_data.pop('meta_data', {})
|
||||
v = ItemVariation.objects.create(item=item, **variation_data)
|
||||
if require_membership_types:
|
||||
v.require_membership_types.add(*require_membership_types)
|
||||
if limit_sales_channels:
|
||||
v.limit_sales_channels.add(*limit_sales_channels)
|
||||
|
||||
if var_meta_data is not None:
|
||||
for key, value in var_meta_data.items():
|
||||
|
||||
@@ -165,7 +165,7 @@ class InlineSeatSerializer(I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Seat
|
||||
fields = ('id', 'name', 'seat_guid')
|
||||
fields = ('id', 'name', 'seat_guid', 'zone_name', 'row_name', 'row_label', 'seat_label', 'seat_number')
|
||||
|
||||
|
||||
class AnswerSerializer(I18nAwareModelSerializer):
|
||||
@@ -585,7 +585,7 @@ class CheckinListOrderPositionSerializer(OrderPositionSerializer):
|
||||
self.fields['item'] = ItemSerializer(read_only=True, context=self.context)
|
||||
|
||||
if 'variation' in self.context['expand']:
|
||||
self.fields['variation'] = InlineItemVariationSerializer(read_only=True)
|
||||
self.fields['variation'] = InlineItemVariationSerializer(read_only=True, context=self.context)
|
||||
|
||||
if 'answers.question' in self.context['expand']:
|
||||
self.fields['answers'].child.fields['question'] = QuestionSerializer(read_only=True)
|
||||
@@ -726,7 +726,7 @@ class OrderSerializer(I18nAwareModelSerializer):
|
||||
'code', 'event', 'status', 'testmode', 'secret', 'email', 'phone', 'locale', 'datetime', 'expires', 'payment_date',
|
||||
'payment_provider', 'fees', 'total', 'comment', 'custom_followup_at', 'invoice_address', 'positions', 'downloads',
|
||||
'checkin_attention', 'checkin_text', 'last_modified', 'payments', 'refunds', 'require_approval', 'sales_channel',
|
||||
'url', 'customer', 'valid_if_pending'
|
||||
'url', 'customer', 'valid_if_pending', 'api_meta'
|
||||
)
|
||||
read_only_fields = (
|
||||
'code', 'status', 'testmode', 'secret', 'datetime', 'expires', 'payment_date',
|
||||
@@ -786,7 +786,7 @@ class OrderSerializer(I18nAwareModelSerializer):
|
||||
# Even though all fields that shouldn't be edited are marked as read_only in the serializer
|
||||
# (hopefully), we'll be extra careful here and be explicit about the model fields we update.
|
||||
update_fields = ['comment', 'custom_followup_at', 'checkin_attention', 'checkin_text', 'email', 'locale',
|
||||
'phone', 'valid_if_pending']
|
||||
'phone', 'valid_if_pending', 'api_meta']
|
||||
|
||||
if 'invoice_address' in validated_data:
|
||||
iadata = validated_data.pop('invoice_address')
|
||||
@@ -1059,7 +1059,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
||||
fields = ('code', 'status', 'testmode', 'email', 'phone', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
|
||||
'invoice_address', 'positions', 'checkin_attention', 'checkin_text', 'payment_info', 'payment_date',
|
||||
'consume_carts', 'force', 'send_email', 'simulate', 'customer', 'custom_followup_at',
|
||||
'require_approval', 'valid_if_pending', 'expires')
|
||||
'require_approval', 'valid_if_pending', 'expires', 'api_meta')
|
||||
|
||||
def validate_payment_provider(self, pp):
|
||||
if pp is None:
|
||||
|
||||
@@ -406,7 +406,7 @@ def _checkin_list_position_queryset(checkinlists, ignore_status=False, ignore_pr
|
||||
'item__variations').select_related('item__tax_rule')
|
||||
|
||||
if expand and 'variation' in expand:
|
||||
qs = qs.prefetch_related('variation')
|
||||
qs = qs.prefetch_related('variation', 'variation__meta_values')
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import serializers, views, viewsets
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.response import Response
|
||||
|
||||
from pretix.api.auth.permission import EventCRUDPermission
|
||||
@@ -162,7 +163,13 @@ class EventViewSet(viewsets.ModelViewSet):
|
||||
qs = filter_qs_by_attr(qs, self.request)
|
||||
|
||||
if 'with_availability_for' in self.request.GET:
|
||||
qs = Event.annotated(qs, channel=self.request.GET.get('with_availability_for'))
|
||||
qs = Event.annotated(
|
||||
qs,
|
||||
channel=get_object_or_404(
|
||||
self.request.organizer.sales_channels,
|
||||
identifier=self.request.GET.get('with_availability_for')
|
||||
)
|
||||
)
|
||||
|
||||
return qs.prefetch_related(
|
||||
'organizer',
|
||||
@@ -436,13 +443,19 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
elif self.request.user.is_authenticated:
|
||||
qs = SubEvent.objects.filter(
|
||||
event__organizer=self.request.organizer,
|
||||
event__in=self.request.user.get_events_with_any_permission()
|
||||
event__in=self.request.user.get_events_with_any_permission(request=self.request)
|
||||
)
|
||||
|
||||
qs = filter_qs_by_attr(qs, self.request)
|
||||
|
||||
if 'with_availability_for' in self.request.GET:
|
||||
qs = SubEvent.annotated(qs, channel=self.request.GET.get('with_availability_for'))
|
||||
qs = SubEvent.annotated(
|
||||
qs,
|
||||
channel=get_object_or_404(
|
||||
self.request.organizer.sales_channels,
|
||||
identifier=self.request.GET.get('with_availability_for')
|
||||
)
|
||||
)
|
||||
|
||||
return qs.prefetch_related(
|
||||
'event',
|
||||
|
||||
@@ -56,10 +56,17 @@ from pretix.base.models import (
|
||||
)
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.helpers.dicts import merge_dicts
|
||||
from pretix.helpers.i18n import i18ncomp
|
||||
|
||||
with scopes_disabled():
|
||||
class ItemFilter(FilterSet):
|
||||
tax_rate = django_filters.CharFilter(method='tax_rate_qs')
|
||||
search = django_filters.CharFilter(method='search_qs')
|
||||
|
||||
def search_qs(self, queryset, name, value):
|
||||
return queryset.filter(
|
||||
Q(internal_name__icontains=value) | Q(name__icontains=i18ncomp(value))
|
||||
)
|
||||
|
||||
def tax_rate_qs(self, queryset, name, value):
|
||||
if value in ("0", "None", "0.00"):
|
||||
@@ -71,6 +78,18 @@ with scopes_disabled():
|
||||
model = Item
|
||||
fields = ['active', 'category', 'admission', 'tax_rate', 'free_price']
|
||||
|
||||
class ItemVariationFilter(FilterSet):
|
||||
search = django_filters.CharFilter(method='search_qs')
|
||||
|
||||
def search_qs(self, queryset, name, value):
|
||||
return queryset.filter(
|
||||
Q(value__icontains=i18ncomp(value))
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = ItemVariation
|
||||
fields = ['active']
|
||||
|
||||
|
||||
class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = ItemSerializer
|
||||
@@ -140,6 +159,7 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = ItemVariationSerializer
|
||||
queryset = ItemVariation.objects.none()
|
||||
filter_backends = (DjangoFilterBackend, TotalOrderingFilter,)
|
||||
filterset_class = ItemVariationFilter
|
||||
ordering_fields = ('id', 'position')
|
||||
ordering = ('id',)
|
||||
permission = None
|
||||
|
||||
@@ -108,6 +108,7 @@ with scopes_disabled():
|
||||
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
|
||||
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
|
||||
created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
|
||||
created_before = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='lt')
|
||||
subevent_after = django_filters.IsoDateTimeFilter(method='subevent_after_qs')
|
||||
subevent_before = django_filters.IsoDateTimeFilter(method='subevent_before_qs')
|
||||
search = django_filters.CharFilter(method='search_qs')
|
||||
@@ -115,6 +116,8 @@ with scopes_disabled():
|
||||
variation = django_filters.CharFilter(field_name='all_positions', lookup_expr='variation_id', distinct=True)
|
||||
subevent = django_filters.CharFilter(field_name='all_positions', lookup_expr='subevent_id', distinct=True)
|
||||
customer = django_filters.CharFilter(field_name='customer__identifier')
|
||||
sales_channel = django_filters.CharFilter(field_name='sales_channel__identifier')
|
||||
payment_provider = django_filters.CharFilter(method='provider_qs')
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
@@ -138,6 +141,11 @@ with scopes_disabled():
|
||||
)
|
||||
return qs
|
||||
|
||||
def provider_qs(self, qs, name, value):
|
||||
return qs.filter(Exists(
|
||||
OrderPayment.objects.filter(order=OuterRef('pk'), provider=value)
|
||||
))
|
||||
|
||||
def subevent_before_qs(self, qs, name, value):
|
||||
if getattr(self.request, 'event', None):
|
||||
subevents = self.request.event.subevents
|
||||
|
||||
@@ -24,10 +24,11 @@ from decimal import Decimal
|
||||
import django_filters
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.db import transaction
|
||||
from django.db.models import OuterRef, Subquery, Sum
|
||||
from django.db.models import OuterRef, Q, Subquery, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import mixins, serializers, status, views, viewsets
|
||||
@@ -136,11 +137,19 @@ class SeatingPlanViewSet(viewsets.ModelViewSet):
|
||||
with scopes_disabled():
|
||||
class GiftCardFilter(FilterSet):
|
||||
secret = django_filters.CharFilter(field_name='secret', lookup_expr='iexact')
|
||||
expired = django_filters.BooleanFilter(method='expired_qs')
|
||||
value = django_filters.NumberFilter(field_name='cached_value')
|
||||
|
||||
class Meta:
|
||||
model = GiftCard
|
||||
fields = ['secret', 'testmode']
|
||||
|
||||
def expired_qs(self, qs, name, value):
|
||||
if value:
|
||||
return qs.filter(expires__isnull=False, expires__lt=now())
|
||||
else:
|
||||
return qs.filter(Q(expires__isnull=True) | Q(expires__gte=now()))
|
||||
|
||||
|
||||
class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = GiftCardSerializer
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import django_filters
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from rest_framework import viewsets
|
||||
|
||||
from pretix.api.models import WebHook
|
||||
@@ -26,11 +28,17 @@ from pretix.api.serializers.webhooks import WebHookSerializer
|
||||
from pretix.helpers.dicts import merge_dicts
|
||||
|
||||
|
||||
class WebhookFilter(FilterSet):
|
||||
enabled = django_filters.rest_framework.BooleanFilter()
|
||||
|
||||
|
||||
class WebHookViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = WebHookSerializer
|
||||
queryset = WebHook.objects.none()
|
||||
permission = 'can_change_organizer_settings'
|
||||
write_permission = 'can_change_organizer_settings'
|
||||
filter_backends = (DjangoFilterBackend,)
|
||||
filterset_class = WebhookFilter
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.organizer.webhooks.prefetch_related('listeners')
|
||||
|
||||
@@ -126,6 +126,17 @@ class ParametrizedOrderWebhookEvent(ParametrizedWebhookEvent):
|
||||
}
|
||||
|
||||
|
||||
class DeletedOrderWebhookEvent(ParametrizedWebhookEvent):
|
||||
def build_payload(self, logentry: LogEntry):
|
||||
return {
|
||||
'notification_id': logentry.pk,
|
||||
'organizer': logentry.organizer.slug,
|
||||
'event': logentry.event.slug,
|
||||
'code': logentry.parsed_data.get("code"),
|
||||
'action': logentry.action_type,
|
||||
}
|
||||
|
||||
|
||||
class ParametrizedEventWebhookEvent(ParametrizedWebhookEvent):
|
||||
|
||||
def build_payload(self, logentry: LogEntry):
|
||||
@@ -297,6 +308,10 @@ def register_default_webhook_events(sender, **kwargs):
|
||||
'pretix.event.order.denied',
|
||||
_('Order denied'),
|
||||
),
|
||||
DeletedOrderWebhookEvent(
|
||||
'pretix.event.order.deleted',
|
||||
_('Order deleted'),
|
||||
),
|
||||
ParametrizedOrderPositionCheckinWebhookEvent(
|
||||
'pretix.event.checkin',
|
||||
_('Ticket checked in'),
|
||||
|
||||
@@ -256,7 +256,7 @@ class ListExporter(BaseExporter):
|
||||
ws = wb.create_sheet()
|
||||
self.prepare_xlsx_sheet(ws)
|
||||
try:
|
||||
ws.title = str(self.verbose_name)
|
||||
ws.title = str(self.verbose_name)[:30]
|
||||
except:
|
||||
pass
|
||||
total = 0
|
||||
@@ -374,7 +374,7 @@ class MultiSheetListExporter(ListExporter):
|
||||
wb = SafeWorkbook(write_only=True)
|
||||
n_sheets = len(self.sheets)
|
||||
for i_sheet, (s, l) in enumerate(self.sheets):
|
||||
ws = wb.create_sheet(str(l))
|
||||
ws = wb.create_sheet(str(l)[:30])
|
||||
if hasattr(self, 'prepare_xlsx_sheet_' + s):
|
||||
getattr(self, 'prepare_xlsx_sheet_' + s)(ws)
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
),
|
||||
).select_related(
|
||||
'order', 'order__invoice_address', 'order__customer', 'item', 'variation',
|
||||
'voucher', 'tax_rule'
|
||||
'voucher', 'tax_rule', 'addon_to',
|
||||
).prefetch_related(
|
||||
'subevent', 'subevent__meta_values',
|
||||
'answers', 'answers__question', 'answers__options'
|
||||
@@ -619,6 +619,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
_('Valid until'),
|
||||
_('Order comment'),
|
||||
_('Follow-up date'),
|
||||
_('Add-on to position ID'),
|
||||
]
|
||||
|
||||
questions = list(Question.objects.filter(event__in=self.events))
|
||||
@@ -652,7 +653,8 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
_('VAT ID'),
|
||||
]
|
||||
headers += [
|
||||
_('Sales channel'), _('Order locale'),
|
||||
_('Sales channel'),
|
||||
_('Order locale'),
|
||||
_('E-mail address verified'),
|
||||
_('External customer ID'),
|
||||
_('Check-in lists'),
|
||||
@@ -743,6 +745,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
]
|
||||
row.append(order.comment)
|
||||
row.append(order.custom_followup_at.strftime("%Y-%m-%d") if order.custom_followup_at else "")
|
||||
row.append(op.addon_to.positionid if op.addon_to_id else "")
|
||||
acache = {}
|
||||
for a in op.answers.all():
|
||||
# We do not want to localize Date, Time and Datetime question answers, as those can lead
|
||||
|
||||
@@ -30,7 +30,7 @@ from typing import Tuple
|
||||
|
||||
import bleach
|
||||
import vat_moss.exchange_rates
|
||||
from bidi.algorithm import get_display
|
||||
from bidi import get_display
|
||||
from django.contrib.staticfiles import finders
|
||||
from django.db.models import Sum
|
||||
from django.dispatch import receiver
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
# Generated by Django 4.2.8 on 2024-07-01 09:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import pretix.base.models.orders
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.13 on 2024-07-17 14:03
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0268_remove_subevent_items_remove_subevent_variations_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='api_meta',
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
]
|
||||
@@ -28,9 +28,9 @@ from django.utils.translation import gettext as _, gettext_lazy, pgettext_lazy
|
||||
|
||||
from pretix.base.modelimport import (
|
||||
BooleanColumnMixin, DatetimeColumnMixin, DecimalColumnMixin, ImportColumn,
|
||||
IntegerColumnMixin, i18n_flat,
|
||||
IntegerColumnMixin, SubeventColumnMixin, i18n_flat,
|
||||
)
|
||||
from pretix.base.models import ItemVariation, Quota, Seat, Voucher
|
||||
from pretix.base.models import ItemVariation, Quota, Seat, SubEvent, Voucher
|
||||
from pretix.base.signals import voucher_import_columns
|
||||
|
||||
|
||||
@@ -55,11 +55,11 @@ class CodeColumn(ImportColumn):
|
||||
obj.code = value
|
||||
|
||||
|
||||
class SubeventColumn(ImportColumn):
|
||||
class SubeventColumn(SubeventColumnMixin, ImportColumn):
|
||||
identifier = 'subevent'
|
||||
verbose_name = pgettext_lazy('subevents', 'Date')
|
||||
|
||||
def assign(self, value, obj: Voucher, **kwargs):
|
||||
def assign(self, value, obj: SubEvent, **kwargs):
|
||||
obj.subevent = value
|
||||
|
||||
|
||||
|
||||
@@ -304,10 +304,13 @@ class EventMixin:
|
||||
return safe_string(json.dumps(eventdict))
|
||||
|
||||
@classmethod
|
||||
def annotated(cls, qs, channel='web', voucher=None):
|
||||
from pretix.base.models import Item, ItemVariation, Quota
|
||||
def annotated(cls, qs, channel, voucher=None):
|
||||
# Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
|
||||
# makes the query SIGNIFICANTLY faster
|
||||
from pretix.base.models import Item, ItemVariation, Quota, SalesChannel
|
||||
|
||||
assert isinstance(channel, (SalesChannel, str))
|
||||
|
||||
assert isinstance(channel, str)
|
||||
sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).filter(
|
||||
Q(variations__isnull=True)
|
||||
& Q(quotas__pk=OuterRef('pk'))
|
||||
@@ -317,18 +320,23 @@ class EventMixin:
|
||||
|
||||
q_variation = (
|
||||
Q(active=True)
|
||||
& Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()))
|
||||
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()))
|
||||
& Q(item__active=True)
|
||||
& Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now()))
|
||||
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now()))
|
||||
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
||||
& Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
||||
& Q(item__require_bundling=False)
|
||||
& Q(quotas__pk=OuterRef('pk'))
|
||||
)
|
||||
|
||||
if isinstance(channel, str):
|
||||
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
||||
else:
|
||||
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
||||
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
|
||||
|
||||
if voucher:
|
||||
if voucher.variation_id:
|
||||
q_variation &= Q(pk=voucher.variation_id)
|
||||
@@ -962,7 +970,7 @@ class Event(EventMixin, LoggedModel):
|
||||
):
|
||||
c_items = list(d.condition_limit_products.all())
|
||||
b_items = list(d.benefit_limit_products.all())
|
||||
limit_sales_channels = list(v.limit_sales_channels.all())
|
||||
limit_sales_channels = list(d.limit_sales_channels.all())
|
||||
d.pk = None
|
||||
d.event = self
|
||||
d._prefetched_objects_cache = {}
|
||||
@@ -1536,8 +1544,11 @@ class SubEvent(EventMixin, LoggedModel):
|
||||
return qs_annotated
|
||||
|
||||
@classmethod
|
||||
def annotated(cls, qs, channel='web', voucher=None):
|
||||
def annotated(cls, qs, channel, voucher=None):
|
||||
from .items import SubEventItem, SubEventItemVariation
|
||||
from .organizer import SalesChannel
|
||||
|
||||
assert isinstance(channel, (str, SalesChannel))
|
||||
|
||||
qs = super().annotated(qs, channel, voucher=voucher)
|
||||
qs = qs.annotate(
|
||||
|
||||
@@ -271,16 +271,24 @@ class SubEventItemVariation(models.Model):
|
||||
|
||||
|
||||
def filter_available(qs, channel='web', voucher=None, allow_addons=False):
|
||||
assert isinstance(channel, str)
|
||||
# Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
|
||||
# makes the query SIGNIFICANTLY faster
|
||||
from .organizer import SalesChannel
|
||||
|
||||
assert isinstance(channel, (SalesChannel, str))
|
||||
q = (
|
||||
# IMPORTANT: If this is updated, also update the ItemVariation query
|
||||
# in models/event.py: EventMixin.annotated()
|
||||
Q(active=True)
|
||||
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()) | Q(available_from_mode='info'))
|
||||
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()) | Q(available_until_mode='info'))
|
||||
& Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||
& Q(require_bundling=False)
|
||||
)
|
||||
if isinstance(channel, str):
|
||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||
else:
|
||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
||||
|
||||
if not allow_addons:
|
||||
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
|
||||
|
||||
|
||||
@@ -299,6 +299,11 @@ class Order(LockModel, LoggedModel):
|
||||
verbose_name=_("Meta information"),
|
||||
null=True, blank=True
|
||||
)
|
||||
api_meta = models.JSONField(
|
||||
verbose_name=_("API meta information"),
|
||||
null=False, blank=True,
|
||||
default=dict
|
||||
)
|
||||
last_modified = models.DateTimeField(
|
||||
auto_now=True, db_index=False
|
||||
)
|
||||
|
||||
@@ -49,7 +49,7 @@ from io import BytesIO
|
||||
|
||||
import jsonschema
|
||||
import reportlab.rl_config
|
||||
from bidi.algorithm import get_display
|
||||
from bidi import get_display
|
||||
from django.conf import settings
|
||||
from django.contrib.staticfiles import finders
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
@@ -275,7 +275,7 @@ class CartManager:
|
||||
}
|
||||
|
||||
def __init__(self, event: Event, cart_id: str, sales_channel: SalesChannel,
|
||||
invoice_address: InvoiceAddress=None, widget_data=None):
|
||||
invoice_address: InvoiceAddress=None, widget_data=None, expiry=None):
|
||||
self.event = event
|
||||
self.cart_id = cart_id
|
||||
self.real_now_dt = now()
|
||||
@@ -287,6 +287,7 @@ class CartManager:
|
||||
self._variations_cache = {}
|
||||
self._seated_cache = {}
|
||||
self._expiry = None
|
||||
self._explicit_expiry = expiry
|
||||
self.invoice_address = invoice_address
|
||||
self._widget_data = widget_data or {}
|
||||
self._sales_channel = sales_channel
|
||||
@@ -305,7 +306,12 @@ class CartManager:
|
||||
return self._seated_cache[item, subevent]
|
||||
|
||||
def _calculate_expiry(self):
|
||||
self._expiry = self.real_now_dt + timedelta(minutes=self.event.settings.get('reservation_time', as_type=int))
|
||||
if self._explicit_expiry:
|
||||
self._expiry = self._explicit_expiry
|
||||
else:
|
||||
self._expiry = self.real_now_dt + timedelta(
|
||||
minutes=self.event.settings.get('reservation_time', as_type=int)
|
||||
)
|
||||
|
||||
def _check_presale_dates(self):
|
||||
if self.event.presale_start and time_machine_now(self.real_now_dt) < self.event.presale_start:
|
||||
|
||||
@@ -960,7 +960,7 @@ def _get_fees(positions: List[CartPosition], payment_requests: List[dict], addre
|
||||
def _create_order(event: Event, *, email: str, positions: List[CartPosition], now_dt: datetime,
|
||||
payment_requests: List[dict], sales_channel: SalesChannel, locale: str=None,
|
||||
address: InvoiceAddress=None, meta_info: dict=None, shown_total=None,
|
||||
customer=None, valid_if_pending=False):
|
||||
customer=None, valid_if_pending=False, api_meta: dict=None):
|
||||
payments = []
|
||||
|
||||
try:
|
||||
@@ -985,6 +985,7 @@ def _create_order(event: Event, *, email: str, positions: List[CartPosition], no
|
||||
total=total,
|
||||
testmode=True if sales_channel.type_instance.testmode_supported and event.testmode else False,
|
||||
meta_info=json.dumps(meta_info or {}),
|
||||
api_meta=api_meta or {},
|
||||
require_approval=require_approval,
|
||||
sales_channel=sales_channel,
|
||||
customer=customer,
|
||||
@@ -1096,7 +1097,7 @@ def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosi
|
||||
|
||||
def _perform_order(event: Event, payment_requests: List[dict], position_ids: List[str],
|
||||
email: str, locale: str, address: int, meta_info: dict=None, sales_channel: str='web',
|
||||
shown_total=None, customer=None):
|
||||
shown_total=None, customer=None, api_meta: dict=None):
|
||||
for p in payment_requests:
|
||||
p['pprov'] = event.get_payment_providers(cached=True)[p['provider']]
|
||||
if not p['pprov']:
|
||||
@@ -1200,7 +1201,8 @@ def _perform_order(event: Event, payment_requests: List[dict], position_ids: Lis
|
||||
sales_channel=sales_channel,
|
||||
shown_total=shown_total,
|
||||
customer=customer,
|
||||
valid_if_pending=valid_if_pending
|
||||
valid_if_pending=valid_if_pending,
|
||||
api_meta=api_meta,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -2042,7 +2044,7 @@ class OrderChangeManager:
|
||||
# This also prevents accidental removal through the UI because a hidden product will no longer
|
||||
# be part of the input.
|
||||
(a.variation and a.variation.unavailability_reason(has_voucher=True, subevent=a.subevent))
|
||||
or (a.variation and self.order.sales_channel not in a.variation.sales_channels)
|
||||
or (a.variation and not a.variation.all_sales_channels and not a.variation.limit_sales_channels.contains(self.order.sales_channel))
|
||||
or a.item.unavailability_reason(has_voucher=True, subevent=a.subevent)
|
||||
or (
|
||||
not item.all_sales_channels and
|
||||
@@ -2873,12 +2875,13 @@ class OrderChangeManager:
|
||||
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,))
|
||||
def perform_order(self, event: Event, payments: List[dict], positions: List[str],
|
||||
email: str=None, locale: str=None, address: int=None, meta_info: dict=None,
|
||||
sales_channel: str='web', shown_total=None, customer=None, override_now_dt: datetime=None):
|
||||
sales_channel: str='web', shown_total=None, customer=None, override_now_dt: datetime=None,
|
||||
api_meta: dict=None):
|
||||
with language(locale), time_machine_now_assigned(override_now_dt):
|
||||
try:
|
||||
try:
|
||||
return _perform_order(event, payments, positions, email, locale, address, meta_info,
|
||||
sales_channel, shown_total, customer)
|
||||
sales_channel, shown_total, customer, api_meta)
|
||||
except LockTimeoutException:
|
||||
self.retry()
|
||||
except (MaxRetriesExceededError, LockTimeoutException):
|
||||
|
||||
@@ -105,6 +105,7 @@ def preview(event: int, provider: str):
|
||||
order = event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
|
||||
email='sample@pretix.eu',
|
||||
locale=event.settings.locale,
|
||||
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
||||
expires=now(), code="PREVIEW1234", total=119)
|
||||
|
||||
scheme = PERSON_NAME_SCHEMES[event.settings.name_scheme]
|
||||
|
||||
@@ -1478,6 +1478,10 @@ DEFAULTS = {
|
||||
min_value=1,
|
||||
required=True,
|
||||
widget=forms.NumberInput(),
|
||||
help_text=_('With an increased limit, a customer may request more than one ticket for a specific product '
|
||||
'using the same, unique email address. However, regardless of this setting, they will need to '
|
||||
'fill the waitlist form multiple times if they want more than one ticket, as every entry only '
|
||||
'grants one single ticket at a time.'),
|
||||
)
|
||||
},
|
||||
'show_checkin_number_user': {
|
||||
|
||||
@@ -40,7 +40,6 @@ from urllib.parse import urlencode
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.uploadedfile import UploadedFile
|
||||
from django.db.models import Max
|
||||
from django.forms.formsets import DELETION_FIELD_NAME
|
||||
from django.urls import reverse
|
||||
@@ -63,9 +62,9 @@ from pretix.base.models import (
|
||||
from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue
|
||||
from pretix.base.signals import item_copy_data
|
||||
from pretix.control.forms import (
|
||||
ButtonGroupRadioSelect, ItemMultipleChoiceField,
|
||||
SalesChannelCheckboxSelectMultiple, SizeValidationMixin,
|
||||
SplitDateTimeField, SplitDateTimePickerWidget,
|
||||
ButtonGroupRadioSelect, ExtFileField, ItemMultipleChoiceField,
|
||||
SalesChannelCheckboxSelectMultiple, SplitDateTimeField,
|
||||
SplitDateTimePickerWidget,
|
||||
)
|
||||
from pretix.control.forms.widgets import Select2, Select2ItemVarMulti
|
||||
from pretix.helpers.models import modelcopy
|
||||
@@ -562,6 +561,13 @@ class TicketNullBooleanSelect(forms.NullBooleanSelect):
|
||||
|
||||
|
||||
class ItemUpdateForm(I18nModelForm):
|
||||
picture = ExtFileField(
|
||||
label=_('Product picture'),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_IMAGE,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_IMAGE,
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tax_rule'].queryset = self.instance.event.tax_rules.all()
|
||||
@@ -751,14 +757,6 @@ class ItemUpdateForm(I18nModelForm):
|
||||
|
||||
return d
|
||||
|
||||
def clean_picture(self):
|
||||
value = self.cleaned_data.get('picture')
|
||||
if isinstance(value, UploadedFile) and value.size > settings.FILE_UPLOAD_MAX_SIZE_IMAGE:
|
||||
raise forms.ValidationError(_("Please do not upload files larger than {size}!").format(
|
||||
size=SizeValidationMixin._sizeof_fmt(settings.FILE_UPLOAD_MAX_SIZE_IMAGE)
|
||||
))
|
||||
return value
|
||||
|
||||
class Meta:
|
||||
model = Item
|
||||
localized_fields = '__all__'
|
||||
|
||||
@@ -58,7 +58,8 @@ from pretix.api.models import WebHook
|
||||
from pretix.api.webhooks import get_all_webhook_events
|
||||
from pretix.base.customersso.oidc import oidc_validate_and_complete_config
|
||||
from pretix.base.forms import (
|
||||
I18nMarkdownTextarea, I18nModelForm, PlaceholderValidator, SettingsForm,
|
||||
SECRET_REDACTED, I18nMarkdownTextarea, I18nModelForm, PlaceholderValidator,
|
||||
SecretKeySettingsField, SettingsForm,
|
||||
)
|
||||
from pretix.base.forms.questions import (
|
||||
NamePartsFormField, WrappedPhoneNumberPrefixWidget, get_country_by_locale,
|
||||
@@ -958,7 +959,7 @@ class SSOProviderForm(I18nModelForm):
|
||||
label=pgettext_lazy('sso_oidc', 'Client ID'),
|
||||
required=False,
|
||||
)
|
||||
config_oidc_client_secret = forms.CharField(
|
||||
config_oidc_client_secret = SecretKeySettingsField(
|
||||
label=pgettext_lazy('sso_oidc', 'Client secret'),
|
||||
required=False,
|
||||
)
|
||||
@@ -1015,7 +1016,13 @@ class SSOProviderForm(I18nModelForm):
|
||||
if self.instance and self.instance.method == method:
|
||||
f.initial = self.instance.configuration.get(suffix)
|
||||
|
||||
def _unmask_secret_fields(self):
|
||||
for k, v in self.cleaned_data.items():
|
||||
if isinstance(self.fields.get(k), SecretKeySettingsField) and self.cleaned_data.get(k) == SECRET_REDACTED:
|
||||
self.cleaned_data[k] = self.fields[k].initial
|
||||
|
||||
def clean(self):
|
||||
self._unmask_secret_fields()
|
||||
data = self.cleaned_data
|
||||
if not data.get("method"):
|
||||
return data
|
||||
|
||||
@@ -98,6 +98,14 @@ class ControlFieldRenderer(FieldRenderer):
|
||||
attrs = ''
|
||||
return '<div class="{klass}"{attrs}>{html}</div>'.format(klass=self.get_form_group_class(), html=html, attrs=attrs)
|
||||
|
||||
def wrap_widget(self, html):
|
||||
if isinstance(self.widget, CheckboxInput):
|
||||
css_class = "checkbox"
|
||||
if self.field.field.disabled:
|
||||
css_class += " disabled"
|
||||
html = f'<div class="{css_class}">{html}</div>'
|
||||
return html
|
||||
|
||||
|
||||
class ControlFieldWithVisibilityRenderer(ControlFieldRenderer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@@ -136,9 +136,15 @@
|
||||
{% if i.tax_rule and i.default_price %}
|
||||
<br/>
|
||||
<small class="text-muted">
|
||||
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name|default:s_taxes %}
|
||||
incl. {{ rate }}% {{ taxname }}
|
||||
{% endblocktrans %}
|
||||
{% if not i.tax_rule.price_includes_tax %}
|
||||
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name %}
|
||||
<strong>plus</strong> {{ rate }}% {{ taxname }}
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name|default:s_taxes %}
|
||||
incl. {{ rate }}% {{ taxname }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
{% for se in request.event.subevents.all %}
|
||||
<option value="{{ se.id }}"
|
||||
{% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}>
|
||||
{{ se.name }} – {{ se.get_date_range_display }}
|
||||
{{ se }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
@@ -119,7 +119,7 @@
|
||||
{% for se in request.event.subevents.all %}
|
||||
<option value="{{ se.id }}"
|
||||
{% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}>
|
||||
{{ se.name }} – {{ se.get_date_range_display }}
|
||||
{{ se }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
@@ -195,7 +195,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if request.event.has_subevents %}
|
||||
<td>{{ e.subevent.name }} – {{ e.subevent.get_date_range_display }}</td>
|
||||
<td>{{ e.subevent }}</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
{{ e.created|date:"SHORT_DATETIME_FORMAT" }}
|
||||
|
||||
@@ -400,7 +400,7 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
|
||||
if key.startswith("plugin:"):
|
||||
module = key.split(":")[1]
|
||||
if value == "enable" and module in plugins_available:
|
||||
if getattr(plugins_available[module].app, 'restricted', False):
|
||||
if getattr(plugins_available[module], 'restricted', False):
|
||||
if module not in request.event.settings.allowed_restricted_plugins:
|
||||
continue
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class ItemList(ListView):
|
||||
def get_queryset(self):
|
||||
return Item.objects.filter(
|
||||
event=self.request.event
|
||||
).annotate(
|
||||
).select_related("tax_rule").annotate(
|
||||
var_count=Count('variations')
|
||||
).prefetch_related("category", "limit_sales_channels").order_by(
|
||||
F('category__position').asc(nulls_first=True),
|
||||
|
||||
@@ -3161,7 +3161,7 @@ class ChannelUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
|
||||
}
|
||||
|
||||
def form_valid(self, form):
|
||||
if form.has_changed() or self.formset.has_changed():
|
||||
if form.has_changed():
|
||||
self.object.log_action('pretix.saleschannel.changed', user=self.request.user, data={
|
||||
k: getattr(self.object, k)
|
||||
for k in form.changed_data
|
||||
|
||||
+1571
-1385
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-24 08:20+0000\n"
|
||||
"PO-Revision-Date: 2024-05-30 17:00+0000\n"
|
||||
"PO-Revision-Date: 2024-07-10 15:00+0000\n"
|
||||
"Last-Translator: Nikolai <nikolai@lengefeldt.de>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
"da/>\n"
|
||||
@@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.5.5\n"
|
||||
"X-Generator: Weblate 5.6.1\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -261,7 +261,7 @@ msgstr ""
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:51
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:60
|
||||
msgid "Ticket not paid"
|
||||
msgstr ""
|
||||
msgstr "Billet ikke betalt"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:52
|
||||
msgid "This ticket is not yet paid. Do you want to continue anyways?"
|
||||
@@ -281,11 +281,11 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:56
|
||||
msgid "Ticket already used"
|
||||
msgstr ""
|
||||
msgstr "Billet allerede i brug"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:57
|
||||
msgid "Information required"
|
||||
msgstr ""
|
||||
msgstr "Kræver information"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
||||
msgid "Unknown ticket"
|
||||
@@ -301,15 +301,15 @@ msgstr "Adgang ikke tilladt"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:62
|
||||
msgid "Ticket code revoked/changed"
|
||||
msgstr ""
|
||||
msgstr "Billetkode trukket tilbage/ændret"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:63
|
||||
msgid "Ticket blocked"
|
||||
msgstr ""
|
||||
msgstr "Billet blokeret"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:64
|
||||
msgid "Ticket not valid at this time"
|
||||
msgstr ""
|
||||
msgstr "Billetten er ikke gyldig på dette tidspunkt"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:65
|
||||
msgid "Order canceled"
|
||||
@@ -317,11 +317,11 @@ msgstr "Bestilling annulleret"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:66
|
||||
msgid "Ticket code is ambiguous on list"
|
||||
msgstr ""
|
||||
msgstr "Billetkoden er flertydig på listen"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:67
|
||||
msgid "Order not approved"
|
||||
msgstr ""
|
||||
msgstr "Bestilling ikke godkendt"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:68
|
||||
#, fuzzy
|
||||
@@ -472,7 +472,7 @@ msgstr "Produktvariation"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:107
|
||||
msgid "Gate"
|
||||
msgstr ""
|
||||
msgstr "Indgang"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:111
|
||||
msgid "Current date and time"
|
||||
@@ -548,7 +548,7 @@ msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:186
|
||||
msgid "Event admission"
|
||||
msgstr ""
|
||||
msgstr "Adgang til arrangementet"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:187
|
||||
msgid "custom date and time"
|
||||
|
||||
@@ -5,7 +5,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-30 18:55+0000\n"
|
||||
"PO-Revision-Date: 2024-06-30 21:07+0000\n"
|
||||
"PO-Revision-Date: 2024-07-19 22:00+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/"
|
||||
">\n"
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.6.1\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
"X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
@@ -3536,7 +3536,7 @@ msgstr "Sie können keinen Ticketcode verwenden, der bereits existiert."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:490
|
||||
msgid "Please enter a valid language code."
|
||||
msgstr "Bitte geben Sie einen gültigen Sprachcode ein."
|
||||
msgstr "Bitte einen gültigen Sprachcode eingeben."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560
|
||||
msgid "Please enter a valid sales channel."
|
||||
@@ -4921,8 +4921,8 @@ msgid ""
|
||||
"The duration of the membership is the same as the duration of the event or "
|
||||
"event series date"
|
||||
msgstr ""
|
||||
"Die Dauer der Mitgliedschaft entspricht der Dauer der Veranstaltung oder des "
|
||||
"Termins"
|
||||
"Die Dauer der Mitgliedschaft entspricht der Dauer der Veranstaltung bzw. in "
|
||||
"Veranstaltungsreihen des gebuchten Termins"
|
||||
|
||||
#: pretix/base/models/items.py:660
|
||||
msgid "Membership duration in days"
|
||||
@@ -9608,7 +9608,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py:1346
|
||||
msgid "Ask search engines not to index the ticket shop"
|
||||
msgstr "Der Ticket-Shop soll von Suchmaschinen nicht indiziert werden"
|
||||
msgstr "Der Ticketshop soll von Suchmaschinen nicht indiziert werden"
|
||||
|
||||
#: pretix/base/settings.py:1355
|
||||
msgid "Show variations of a product expanded by default"
|
||||
@@ -10874,7 +10874,7 @@ msgstr ""
|
||||
"Sie haben sich auf die Warteliste für {event} \n"
|
||||
"für das Produkt {product} eingetragen.\n"
|
||||
"\n"
|
||||
"Wir haben nun ein Ticket für Sie! Sie können es in unserem Ticket-Shop "
|
||||
"Wir haben nun ein Ticket für Sie! Sie können es in unserem Ticketshop "
|
||||
"erwerben,\n"
|
||||
"indem Sie in den nächsten {hours} Stunden den folgenden Gutscheincode "
|
||||
"eingeben:\n"
|
||||
@@ -11971,7 +11971,7 @@ msgid ""
|
||||
"If you just configured this as a domain for your ticket shop, you now need "
|
||||
"to set this up as a \"custom domain\" in your organizer account."
|
||||
msgstr ""
|
||||
"Wenn Sie gerade diese Domain für Ihren Ticket-Shop eingerichtet haben, "
|
||||
"Wenn Sie gerade diese Domain für Ihren Ticketshop eingerichtet haben, "
|
||||
"müssen Sie diese nun in Ihrem Veranstalterkonto als \"eigene Domain\" "
|
||||
"eintragen."
|
||||
|
||||
@@ -18403,7 +18403,7 @@ msgid ""
|
||||
"You can instead take your shop offline. This will hide it from everyone "
|
||||
"except from the organizer teams you configured to have access to the event."
|
||||
msgstr ""
|
||||
"Sie können stattdessen den Ticket-Shop abschalten. Dies wird die "
|
||||
"Sie können stattdessen den Ticketshop abschalten. Dies wird die "
|
||||
"Veranstaltung vor allen außer den zugewiesenen Veranstalter-Teams verstecken."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html:66
|
||||
@@ -18629,14 +18629,14 @@ msgid ""
|
||||
"Your ticket shop is currently not live. It is thus only visible to you and "
|
||||
"your team, not to any visitors."
|
||||
msgstr ""
|
||||
"Ihr Ticket-Shop ist zur Zeit offline und daher nur für Sie und Ihr Team "
|
||||
"Ihr Ticketshop ist zur Zeit offline und daher nur für Sie und Ihr Team "
|
||||
"verfügbar und nicht für Besucher."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:41
|
||||
msgid ""
|
||||
"To publish your ticket shop, you first need to resolve the following issues:"
|
||||
msgstr ""
|
||||
"Um Ihren Ticket-Shop zu veröffentlichen, müssen Sie zuerst die folgenden "
|
||||
"Um Ihren Ticketshop zu veröffentlichen, müssen Sie zuerst die folgenden "
|
||||
"Probleme beheben:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:51
|
||||
@@ -18646,7 +18646,7 @@ msgstr "Shop veröffentlichen"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:59
|
||||
msgid "If you want to, you can publish your ticket shop now."
|
||||
msgstr "Sie können Ihren Ticket-Shop jederzeit veröffentlichen."
|
||||
msgstr "Sie können Ihren Ticketshop jederzeit veröffentlichen."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:83
|
||||
msgid ""
|
||||
@@ -19488,7 +19488,7 @@ msgid ""
|
||||
"website. This way, your visitors can buy their ticket right away without "
|
||||
"leaving your website."
|
||||
msgstr ""
|
||||
"Das pretix-Widget ist ein Weg, den Ticket-Shop in Ihre Event-Website "
|
||||
"Das pretix-Widget ist ein Weg, den Ticketshop in Ihre Event-Website "
|
||||
"einzubetten. Auf diese Weise können Besucher Ihrer Website ein Ticket "
|
||||
"erwerben, ohne die Website verlassen zu müssen."
|
||||
|
||||
@@ -19515,7 +19515,7 @@ msgid ""
|
||||
"JavaScript is disabled in your browser. To access our ticket shop without "
|
||||
"JavaScript, please <a %(a_attr)s>click here</a>."
|
||||
msgstr ""
|
||||
"JavaScript ist in Ihrem Browser deaktiviert. Um unseren Ticket-Shop ohne "
|
||||
"JavaScript ist in Ihrem Browser deaktiviert. Um unseren Ticketshop ohne "
|
||||
"JavaScript aufzurufen, klicken Sie bitte <a %(a_attr)s>hier</a>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/widget.html:64
|
||||
@@ -19580,7 +19580,7 @@ msgid ""
|
||||
"less than 10 characters that can be easily remembered, but you can also "
|
||||
"choose to use a random value."
|
||||
msgstr ""
|
||||
"Dies ist die Adresse, unter der Ihr Ticket-Shop verfügbar sein wird. Sie "
|
||||
"Dies ist die Adresse, unter der Ihr Ticketshop verfügbar sein wird. Sie "
|
||||
"sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Punkte und "
|
||||
"Bindestriche enthalten. Sie muss unter Ihren Veranstaltungen einmalig sein. "
|
||||
"Wir empfehlen eine Abkürzung oder ein Datum mit weniger als 10 Zeichen, das "
|
||||
@@ -22464,7 +22464,7 @@ msgstr "Veröffentlichen Sie Ihren Shop"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html:27
|
||||
msgid "Go to the ticket shop"
|
||||
msgstr "Zum Ticket-Shop"
|
||||
msgstr "Zum Ticketshop"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html:35
|
||||
msgid "Search query:"
|
||||
@@ -23102,7 +23102,7 @@ msgid ""
|
||||
"usage, the legal details in your specific jurisdiction, or the agreements "
|
||||
"you have with third parties such as payment or tracking providers."
|
||||
msgstr ""
|
||||
"Trotzdem bleibt es Ihre Verantwortung, dass Ihr Ticket-Shop allen "
|
||||
"Trotzdem bleibt es Ihre Verantwortung, dass Ihr Ticketshop allen "
|
||||
"anwendbaren Gesetzen entspricht. Wir versuchen mit diesen Einstellungen zu "
|
||||
"helfen, aber können keine Haftung übernehmen, da wir unter anderem die "
|
||||
"genaue Konfiguration Ihres Ticketshops, die rechtlichen Details der "
|
||||
@@ -25624,7 +25624,7 @@ msgstr "{quota} übrig"
|
||||
|
||||
#: pretix/control/views/dashboards.py:269
|
||||
msgid "Your ticket shop is"
|
||||
msgstr "Ihr Ticket-Shop ist"
|
||||
msgstr "Ihr Ticketshop ist"
|
||||
|
||||
#: pretix/control/views/dashboards.py:269
|
||||
msgid "Click here to change"
|
||||
@@ -31490,7 +31490,7 @@ msgstr "Warnung"
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:127
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:201
|
||||
msgid "This ticket shop is currently in test mode."
|
||||
msgstr "Dieser Ticket-Shop ist momentan im Testmodus."
|
||||
msgstr "Dieser Ticketshop ist momentan im Testmodus."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:130
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:204
|
||||
@@ -32857,7 +32857,7 @@ msgstr "Shop ausgeschaltet"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/offline.html:9
|
||||
msgid "This ticket shop is currently turned off."
|
||||
msgstr "Dieser Ticket-Shop ist im Moment nicht aktiv."
|
||||
msgstr "Dieser Ticketshop ist im Moment nicht aktiv."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/offline.html:10
|
||||
msgid "It is only accessible to authenticated team members."
|
||||
@@ -33684,7 +33684,7 @@ msgid ""
|
||||
"open source ticket sales software</a>."
|
||||
msgstr ""
|
||||
"Dies ist eine selbst-gehostete Installation von <a %(a_attr)s>pretix, dem "
|
||||
"freundlichen Open Source Ticket-Shop</a>."
|
||||
"freundlichen Open Source Ticketshop</a>."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/index.html:15
|
||||
msgid ""
|
||||
@@ -34215,7 +34215,7 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/views/widget.py:372
|
||||
msgid "This ticket shop is currently disabled."
|
||||
msgstr "Dieser Ticket-Shop ist im Moment nicht verfügbar."
|
||||
msgstr "Dieser Ticketshop ist im Moment nicht verfügbar."
|
||||
|
||||
#: pretix/presale/views/widget.py:386
|
||||
msgid "The selected date does not exist in this event series."
|
||||
@@ -34336,7 +34336,7 @@ msgstr "Kosovo"
|
||||
#~ msgstr "Sie können nicht fortfahren."
|
||||
|
||||
#~ msgid "The selected ticket shop is currently not available."
|
||||
#~ msgstr "Der ausgewählte Ticket-Shop ist im Moment nicht verfügbar."
|
||||
#~ msgstr "Der ausgewählte Ticketshop ist im Moment nicht verfügbar."
|
||||
|
||||
#~ msgid "Needs to be enabled in your Stripe account first."
|
||||
#~ msgstr "Muss erst im Stripe-Account aktiviert werden."
|
||||
|
||||
@@ -871,12 +871,12 @@ msgstr "minimale Bestellmenge: %s"
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:39
|
||||
msgctxt "widget"
|
||||
msgid "Close ticket shop"
|
||||
msgstr "Ticket-Shop schließen"
|
||||
msgstr "Ticketshop schließen"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:40
|
||||
msgctxt "widget"
|
||||
msgid "The ticket shop could not be loaded."
|
||||
msgstr "Der Ticket-Shop konnte nicht geladen werden."
|
||||
msgstr "Der Ticketshop konnte nicht geladen werden."
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||
msgctxt "widget"
|
||||
@@ -890,7 +890,7 @@ msgstr ""
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
||||
msgctxt "widget"
|
||||
msgid "Open ticket shop"
|
||||
msgstr "Ticket-Shop öffnen"
|
||||
msgstr "Ticketshop öffnen"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||
msgctxt "widget"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-30 18:55+0000\n"
|
||||
"PO-Revision-Date: 2024-06-30 21:07+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"PO-Revision-Date: 2024-07-20 13:00+0000\n"
|
||||
"Last-Translator: JnnisCanis <me@jnnis.de>\n"
|
||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||
"pretix/pretix/de_Informal/>\n"
|
||||
"Language: de_Informal\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.6.1\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -3536,7 +3536,7 @@ msgstr "Sie können keinen Ticketcode verwenden, der bereits existiert."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:490
|
||||
msgid "Please enter a valid language code."
|
||||
msgstr "Bitte gib einen gültigen Sprachcode ein."
|
||||
msgstr "Bitte einen gültigen Sprachcode eingeben."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560
|
||||
msgid "Please enter a valid sales channel."
|
||||
@@ -4917,8 +4917,8 @@ msgid ""
|
||||
"The duration of the membership is the same as the duration of the event or "
|
||||
"event series date"
|
||||
msgstr ""
|
||||
"Die Dauer der Mitgliedschaft entspricht der Dauer der Veranstaltung oder des "
|
||||
"Termins"
|
||||
"Die Dauer der Mitgliedschaft entspricht der Dauer der Veranstaltung bzw. in "
|
||||
"Veranstaltungsreihen des gebuchten Termins"
|
||||
|
||||
#: pretix/base/models/items.py:660
|
||||
msgid "Membership duration in days"
|
||||
@@ -6671,11 +6671,10 @@ msgid ""
|
||||
"rel=\"noopener\">Click here for detailed information on what this does.</a> "
|
||||
"Don't forget to set the correct fees above!"
|
||||
msgstr ""
|
||||
"Wir empfehlen, diese Option zu aktivieren, wenn du die Gebühren Ihres "
|
||||
"Zahlungsdienstleisters an Ihre Kunden weitergeben willst. Denk daran, oben "
|
||||
"die richtigen Gebührensätze des Zahlungsanbieters einzustellen. <a "
|
||||
"href=\"{docs_url}\" target=\"_blank\" rel=\"noopener\">Weitere "
|
||||
"Informationen</a>."
|
||||
"Wir empfehlen, diese Option zu aktivieren, wenn Du die Gebühren deines "
|
||||
"Zahlungsdienstleisters an deine Kunden weitergeben willst. Denke daran, oben "
|
||||
"die richtigen Gebührensätze des Zahlungsanbieters einzustellen. <a href=\""
|
||||
"{docs_url}\" target=\"_blank\" rel=\"noopener\">Weitere Informationen</a>."
|
||||
|
||||
#: pretix/base/payment.py:394
|
||||
msgid "Text on invoices"
|
||||
@@ -9239,9 +9238,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Anzahl an Minuten, die ein Benutzer nach Abschicken der Bestellung hat, um "
|
||||
"die Zahlung abzuschließen. Benutze dies nur, wenn du ausschließlich "
|
||||
"Zahlungsmethoden mit sofortiger Bestätigung anbietest. Bitte beachte das das "
|
||||
"tatsächliche Zeitfenster aus technischen Gründen einige Minuten länger sein "
|
||||
"kann."
|
||||
"Zahlungsmethoden mit sofortiger Bestätigung anbietest. Bitte beachte, dass "
|
||||
"das tatsächliche Zeitfenster aus technischen Gründen einige Minuten länger "
|
||||
"sein kann."
|
||||
|
||||
#: pretix/base/settings.py:920
|
||||
msgid "Last date of payments"
|
||||
@@ -9594,7 +9593,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py:1346
|
||||
msgid "Ask search engines not to index the ticket shop"
|
||||
msgstr "Der Ticket-Shop soll von Suchmaschinen nicht indiziert werden"
|
||||
msgstr "Der Ticketshop soll von Suchmaschinen nicht indiziert werden"
|
||||
|
||||
#: pretix/base/settings.py:1355
|
||||
msgid "Show variations of a product expanded by default"
|
||||
@@ -9914,7 +9913,8 @@ msgstr "Keine Änderungen an bestehenden Bestellungen"
|
||||
#: pretix/base/settings.py:1665 pretix/base/settings.py:1674
|
||||
msgid "Only the person who ordered can make changes"
|
||||
msgstr ""
|
||||
"Nur die Person, die die Bestellung aufgegeben hat, kann Änderungen vornehmen"
|
||||
"Nur die Person, welche die Bestellung aufgegeben hat, kann Änderungen "
|
||||
"vornehmen"
|
||||
|
||||
#: pretix/base/settings.py:1666 pretix/base/settings.py:1675
|
||||
msgid "Both the attendee and the person who ordered can make changes"
|
||||
@@ -10854,9 +10854,9 @@ msgstr ""
|
||||
"Hallo,\n"
|
||||
"\n"
|
||||
"du hast dich auf die Warteliste für {event} \n"
|
||||
"für das Produkt {product} eingetragen.\n"
|
||||
"und das Produkt {product} eingetragen.\n"
|
||||
"\n"
|
||||
"Wir haben nun ein Ticket für dich! Du kannst es in unserem Ticket-Shop "
|
||||
"Wir haben nun ein Ticket für dich! Du kannst es in unserem Ticketshop "
|
||||
"erwerben,\n"
|
||||
"indem du in den nächsten {hours} Stunden den folgenden Gutscheincode "
|
||||
"eingibst:\n"
|
||||
@@ -10872,9 +10872,8 @@ msgstr ""
|
||||
"weitergeben,\n"
|
||||
"wenn du den Gutschein nicht in diesem Zeitraum einlöst.\n"
|
||||
"\n"
|
||||
"Wenn du das Ticket NICHT mehr möchtest, bitten wir dich folgenden Link zu "
|
||||
"klicken\n"
|
||||
"um uns Bescheid zu sagen. So können wir das Ticket schnellstmöglich an die "
|
||||
"Wenn du das Ticket NICHT mehr möchtest, sag uns bitte durch Klicken auf "
|
||||
"folgenden Link Bescheid. So können wir das Ticket schnellstmöglich an die "
|
||||
"nächste\n"
|
||||
"wartende Person auf der Warteliste weitergeben:\n"
|
||||
"\n"
|
||||
@@ -11950,7 +11949,7 @@ msgid ""
|
||||
"If you just configured this as a domain for your ticket shop, you now need "
|
||||
"to set this up as a \"custom domain\" in your organizer account."
|
||||
msgstr ""
|
||||
"Wenn du gerade diese Domain für deinen Ticket-Shop eingerichtet hast, musst "
|
||||
"Wenn du gerade diese Domain für deinen Ticketshop eingerichtet hast, musst "
|
||||
"du diese nun in deinem Veranstalterkonto als \"eigene Domain\" eintragen."
|
||||
|
||||
#: pretix/base/templates/403.html:4 pretix/base/templates/403.html:8
|
||||
@@ -13976,7 +13975,7 @@ msgid ""
|
||||
"set the name here."
|
||||
msgstr ""
|
||||
"Wenn du den \"powered by\"-Text in der Fußzeile anpassen willst, um den "
|
||||
"Namen Ihrer Firma oder Organisation aufzunehmen (wenn du Änderungen an "
|
||||
"Namen deiner Firma oder Organisation aufzunehmen (wenn du Änderungen an "
|
||||
"pretix vorgenommen hast), kannst du hier den Namen eintragen."
|
||||
|
||||
#: pretix/control/forms/global_settings.py:205
|
||||
@@ -14641,7 +14640,7 @@ msgstr ""
|
||||
"Erstattungen angezeigt. Wenn diese Option mit der Option für automatische "
|
||||
"Erstattungen kombiniert wird, werden ausschließlich Zahlungen mit einer "
|
||||
"Zahlungsart, die keine automatischen Erstattungen unterstützt, automatisch "
|
||||
"als manuelle Erstattungen auf Ihrer Erstattungsliste als \"zu erledigen\" "
|
||||
"als manuelle Erstattungen auf deiner Erstattungsliste als \"zu erledigen\" "
|
||||
"auftauchen. Wähle diese Option nicht, wenn du Bestellungen mit anderen "
|
||||
"Bestellungen verrechnen oder als Gutschein erstatten möchtest."
|
||||
|
||||
@@ -17466,7 +17465,7 @@ msgstr "Filter"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html:50
|
||||
msgid "Your search did not match any check-ins."
|
||||
msgstr "Ihre Filter treffen auf keine Check-ins zu."
|
||||
msgstr "Deine Filter treffen auf keine Check-ins zu."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html:52
|
||||
msgid "You haven't scanned any tickets yet."
|
||||
@@ -18371,7 +18370,7 @@ msgid ""
|
||||
"You can instead take your shop offline. This will hide it from everyone "
|
||||
"except from the organizer teams you configured to have access to the event."
|
||||
msgstr ""
|
||||
"Du kannst stattdessen den Ticket-Shop abschalten. Dies wird die "
|
||||
"Du kannst stattdessen den Ticketshop abschalten. Dies wird die "
|
||||
"Veranstaltung vor allen außer den zugewiesenen Veranstalter-Teams verstecken."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html:66
|
||||
@@ -18596,14 +18595,14 @@ msgid ""
|
||||
"Your ticket shop is currently not live. It is thus only visible to you and "
|
||||
"your team, not to any visitors."
|
||||
msgstr ""
|
||||
"Dein Ticket-Shop ist zur Zeit offline und daher nur für dich und dein Team "
|
||||
"Dein Ticketshop ist zur Zeit offline und daher nur für dich und dein Team "
|
||||
"verfügbar und nicht für Besucher."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:41
|
||||
msgid ""
|
||||
"To publish your ticket shop, you first need to resolve the following issues:"
|
||||
msgstr ""
|
||||
"Um deinen Ticket-Shop zu veröffentlichen, musst du zuerst die folgenden "
|
||||
"Um deinen Ticketshop zu veröffentlichen, musst du zuerst die folgenden "
|
||||
"Probleme beheben:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:51
|
||||
@@ -18613,7 +18612,7 @@ msgstr "Shop veröffentlichen"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:59
|
||||
msgid "If you want to, you can publish your ticket shop now."
|
||||
msgstr "Du kannst deinen Ticket-Shop jederzeit veröffentlichen."
|
||||
msgstr "Du kannst deinen Ticketshop jederzeit veröffentlichen."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html:83
|
||||
msgid ""
|
||||
@@ -19454,7 +19453,7 @@ msgid ""
|
||||
"website. This way, your visitors can buy their ticket right away without "
|
||||
"leaving your website."
|
||||
msgstr ""
|
||||
"Das pretix-Widget ist ein Weg, den Ticket-Shop in deine Event-Website "
|
||||
"Das pretix-Widget ist ein Weg, den Ticketshop in deine Event-Website "
|
||||
"einzubetten. Auf diese Weise können Besucher deiner Website ein Ticket "
|
||||
"erwerben, ohne die Website verlassen zu müssen."
|
||||
|
||||
@@ -19481,7 +19480,7 @@ msgid ""
|
||||
"JavaScript is disabled in your browser. To access our ticket shop without "
|
||||
"JavaScript, please <a %(a_attr)s>click here</a>."
|
||||
msgstr ""
|
||||
"JavaScript ist in deinem Browser deaktiviert. Um unseren Ticket-Shop ohne "
|
||||
"JavaScript ist in deinem Browser deaktiviert. Um unseren Ticketshop ohne "
|
||||
"JavaScript aufzurufen, klicke bitte <a %(a_attr)s>hier</a>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/widget.html:64
|
||||
@@ -19546,7 +19545,7 @@ msgid ""
|
||||
"less than 10 characters that can be easily remembered, but you can also "
|
||||
"choose to use a random value."
|
||||
msgstr ""
|
||||
"Dies ist die Adresse, unter der dein Ticket-Shop verfügbar sein wird. Sie "
|
||||
"Dies ist die Adresse, unter der dein Ticketshop verfügbar sein wird. Sie "
|
||||
"sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Punkte und "
|
||||
"Bindestriche enthalten. Sie muss unter deinen Veranstaltungen einmalig sein. "
|
||||
"Wir empfehlen eine Abkürzung oder ein Datum mit unter 10 Zeichen, das man "
|
||||
@@ -19807,7 +19806,7 @@ msgid ""
|
||||
"usage of pretix is in compliance with the Enterprise license you purchased."
|
||||
msgstr ""
|
||||
"Der Bericht dient zwei Zwecken: Dem Sammeln nützlicher Informationen um "
|
||||
"Probleme mit Ihrer pretix-Installation zu analysieren und um zu überprüfen, "
|
||||
"Probleme mit deiner pretix-Installation zu analysieren und um zu überprüfen, "
|
||||
"dass deine Nutzung von pretix von der erworbenen pretix-Enterprise-Lizenz "
|
||||
"abgedeckt ist."
|
||||
|
||||
@@ -22425,7 +22424,7 @@ msgstr "Veröffentliche deinen Shop"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html:27
|
||||
msgid "Go to the ticket shop"
|
||||
msgstr "Zum Ticket-Shop"
|
||||
msgstr "Zum Ticketshop"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html:35
|
||||
msgid "Search query:"
|
||||
@@ -23063,7 +23062,7 @@ msgid ""
|
||||
"usage, the legal details in your specific jurisdiction, or the agreements "
|
||||
"you have with third parties such as payment or tracking providers."
|
||||
msgstr ""
|
||||
"Trotzdem bleibt es deine Verantwortung, dass dein Ticket-Shop allen "
|
||||
"Trotzdem bleibt es deine Verantwortung, dass dein Ticketshop allen "
|
||||
"anwendbaren Gesetzen entspricht. Wir versuchen mit diesen Einstellungen zu "
|
||||
"helfen, aber können keine Haftung übernehmen, da wir unter anderem die "
|
||||
"genaue Konfiguration deines Ticketshops, die rechtlichen Details der "
|
||||
@@ -25579,7 +25578,7 @@ msgstr "{quota} übrig"
|
||||
|
||||
#: pretix/control/views/dashboards.py:269
|
||||
msgid "Your ticket shop is"
|
||||
msgstr "Dein Ticket-Shop ist"
|
||||
msgstr "Dein Ticketshop ist"
|
||||
|
||||
#: pretix/control/views/dashboards.py:269
|
||||
msgid "Click here to change"
|
||||
@@ -30131,7 +30130,7 @@ msgid ""
|
||||
"generate you API keys with the recommended permission level for optimal "
|
||||
"usage with pretix."
|
||||
msgstr ""
|
||||
"Der Button oben wird unsere Stripe-App in Ihrem Stripe-Konto installieren "
|
||||
"Der obige Button wird unsere Stripe-App in deinem Stripe-Konto installieren "
|
||||
"und API-Schlüssel mit dem empfohlenen Berechtigungslevel für die Verwendung "
|
||||
"mit pretix generieren."
|
||||
|
||||
@@ -30382,7 +30381,7 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:992
|
||||
msgid "Your payment failed. Please try again."
|
||||
msgstr "Ihre Zahlung ist fehlgeschlagen, bitte erneut versuchen."
|
||||
msgstr "Deine Zahlung ist fehlgeschlagen. Bitte versuche es erneut."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:998
|
||||
#, python-format
|
||||
@@ -31432,7 +31431,7 @@ msgstr "Warnung"
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:127
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:201
|
||||
msgid "This ticket shop is currently in test mode."
|
||||
msgstr "Dieser Ticket-Shop ist momentan im Testmodus."
|
||||
msgstr "Dieser Ticketshop ist momentan im Testmodus."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:130
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:204
|
||||
@@ -32466,7 +32465,7 @@ msgid ""
|
||||
"If you click the link in our email, you will be able to download your "
|
||||
"tickets here."
|
||||
msgstr ""
|
||||
"Wenn du den Link in Ihrer E-Mail anklickst, kannst du deine Tickets hier "
|
||||
"Wenn du den Link in deiner E-Mail anklickst, kannst du deine Tickets hier "
|
||||
"herunterladen."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_downloads.html:30
|
||||
@@ -32794,7 +32793,7 @@ msgstr "Shop ausgeschaltet"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/offline.html:9
|
||||
msgid "This ticket shop is currently turned off."
|
||||
msgstr "Dieser Ticket-Shop ist im Moment nicht aktiv."
|
||||
msgstr "Dieser Ticketshop ist im Moment nicht aktiv."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/offline.html:10
|
||||
msgid "It is only accessible to authenticated team members."
|
||||
@@ -33622,7 +33621,7 @@ msgid ""
|
||||
"open source ticket sales software</a>."
|
||||
msgstr ""
|
||||
"Dies ist eine selbst-gehostete Installation von <a %(a_attr)s>pretix, dem "
|
||||
"freundlichen Open Source Ticket-Shop</a>."
|
||||
"freundlichen Open Source Ticketshop</a>."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/index.html:15
|
||||
msgid ""
|
||||
@@ -33691,7 +33690,7 @@ msgstr "Konto erstellen"
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:7
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:10
|
||||
msgid "Your membership"
|
||||
msgstr "Ihre Mitgliedschaft"
|
||||
msgstr "Deine Mitgliedschaft"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_password.html:6
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_resetpw.html:6
|
||||
@@ -34150,7 +34149,7 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/views/widget.py:372
|
||||
msgid "This ticket shop is currently disabled."
|
||||
msgstr "Dieser Ticket-Shop ist im Moment nicht verfügbar."
|
||||
msgstr "Dieser Ticketshop ist im Moment nicht verfügbar."
|
||||
|
||||
#: pretix/presale/views/widget.py:386
|
||||
msgid "The selected date does not exist in this event series."
|
||||
@@ -34271,7 +34270,7 @@ msgstr "Kosovo"
|
||||
#~ msgstr "Du kannst daher nicht fortfahren."
|
||||
|
||||
#~ msgid "The selected ticket shop is currently not available."
|
||||
#~ msgstr "Der ausgewählte Ticket-Shop ist im Moment nicht verfügbar."
|
||||
#~ msgstr "Der ausgewählte Ticketshop ist im Moment nicht verfügbar."
|
||||
|
||||
#~ msgid "Needs to be enabled in your Stripe account first."
|
||||
#~ msgstr "Muss erst im Stripe-Account aktiviert werden."
|
||||
|
||||
@@ -870,12 +870,12 @@ msgstr "minimale Bestellmenge: %s"
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:39
|
||||
msgctxt "widget"
|
||||
msgid "Close ticket shop"
|
||||
msgstr "Ticket-Shop schließen"
|
||||
msgstr "Ticketshop schließen"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:40
|
||||
msgctxt "widget"
|
||||
msgid "The ticket shop could not be loaded."
|
||||
msgstr "Der Ticket-Shop konnte nicht geladen werden."
|
||||
msgstr "Der Ticketshop konnte nicht geladen werden."
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||
msgctxt "widget"
|
||||
@@ -889,7 +889,7 @@ msgstr ""
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
||||
msgctxt "widget"
|
||||
msgid "Open ticket shop"
|
||||
msgstr "Ticket-Shop öffnen"
|
||||
msgstr "Ticketshop öffnen"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||
msgctxt "widget"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-24 08:20+0000\n"
|
||||
"PO-Revision-Date: 2024-06-25 01:00+0000\n"
|
||||
"PO-Revision-Date: 2024-07-19 08:56+0000\n"
|
||||
"Last-Translator: Reece Needham <nouveaureece@protonmail.com>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/es/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.5.5\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -254,7 +254,7 @@ msgstr "Cancelar"
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:51
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:60
|
||||
msgid "Ticket not paid"
|
||||
msgstr "Ticket por pagar"
|
||||
msgstr "Entrada no pagada"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:52
|
||||
msgid "This ticket is not yet paid. Do you want to continue anyways?"
|
||||
@@ -274,7 +274,7 @@ msgstr "Salida registrada"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:56
|
||||
msgid "Ticket already used"
|
||||
msgstr "Este ticket ya fue utilizado"
|
||||
msgstr "Esta entrada ya fue utilizada"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:57
|
||||
msgid "Information required"
|
||||
@@ -282,11 +282,11 @@ msgstr "Información requerida"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
||||
msgid "Unknown ticket"
|
||||
msgstr "Ticket no encontrado"
|
||||
msgstr "Entrada desconocida"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:59
|
||||
msgid "Ticket type not allowed here"
|
||||
msgstr "Tipo de ticket no está permitido"
|
||||
msgstr "Tipo de entrada no está permitido"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:61
|
||||
msgid "Entry not allowed"
|
||||
@@ -294,19 +294,19 @@ msgstr "Entrada no permitida"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:62
|
||||
msgid "Ticket code revoked/changed"
|
||||
msgstr "Código de ticket revocado/cambiado"
|
||||
msgstr "Código de entrada revocada/cambiada"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:63
|
||||
msgid "Ticket blocked"
|
||||
msgstr "Ticket bloqueado"
|
||||
msgstr "Entrada bloqueada"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:64
|
||||
msgid "Ticket not valid at this time"
|
||||
msgstr "Ticket no válido en este momento"
|
||||
msgstr "Entrada no válida en este momento"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:65
|
||||
msgid "Order canceled"
|
||||
msgstr "Orden cancelada"
|
||||
msgstr "Pedido cancelado"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:66
|
||||
msgid "Ticket code is ambiguous on list"
|
||||
@@ -591,7 +591,7 @@ msgstr "Objeto"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/editor.js:673
|
||||
msgid "Ticket design"
|
||||
msgstr "Diseño del ticket"
|
||||
msgstr "Diseño del entrada"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/editor.js:972
|
||||
msgid "Saving failed."
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,16 +7,16 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-30 18:55+0000\n"
|
||||
"PO-Revision-Date: 2024-04-19 23:00+0000\n"
|
||||
"Last-Translator: Christiaan de Die le Clercq <contact@techwolf12.nl>\n"
|
||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/"
|
||||
">\n"
|
||||
"PO-Revision-Date: 2024-07-11 02:00+0000\n"
|
||||
"Last-Translator: Dirk-jan mollema <dirkjan@outsidersecurity.nl>\n"
|
||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/>"
|
||||
"\n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.4.3\n"
|
||||
"X-Generator: Weblate 5.6.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -25927,10 +25927,8 @@ msgstr "Voucherhistorie"
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/import_start.html:6
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html:81
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html:94
|
||||
#, fuzzy
|
||||
#| msgid "Import mode"
|
||||
msgid "Import vouchers"
|
||||
msgstr "Importmodus"
|
||||
msgstr "Importeer vouchers"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html:10
|
||||
msgid ""
|
||||
@@ -33194,10 +33192,8 @@ msgid "There are no add-ons available for this product."
|
||||
msgstr "Er zijn geen add-ons beschikbaar voor dit product."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_availability.html:6
|
||||
#, fuzzy
|
||||
#| msgid "Enter a voucher code below to buy this ticket."
|
||||
msgid "Enter a voucher code below to buy this product."
|
||||
msgstr "Voer hieronder een vouchercode in om dit ticket te kopen."
|
||||
msgstr "Voer hieronder een vouchercode in om dit product te kopen."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_availability.html:10
|
||||
#, fuzzy
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-30 18:55+0000\n"
|
||||
"PO-Revision-Date: 2024-06-27 17:00+0000\n"
|
||||
"PO-Revision-Date: 2024-07-01 16:00+0000\n"
|
||||
"Last-Translator: Anarion Dunedain <anarion80@gmail.com>\n"
|
||||
"Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix/pl/"
|
||||
">\n"
|
||||
@@ -122,7 +122,7 @@ msgstr "Słowacki"
|
||||
|
||||
#: pretix/_base_settings.py:103
|
||||
msgid "Swedish"
|
||||
msgstr ""
|
||||
msgstr "Szwedzki"
|
||||
|
||||
#: pretix/_base_settings.py:104
|
||||
msgid "Spanish"
|
||||
@@ -640,13 +640,15 @@ msgstr "Sklep online"
|
||||
|
||||
#: pretix/base/channels.py:174
|
||||
msgid "API"
|
||||
msgstr ""
|
||||
msgstr "API"
|
||||
|
||||
#: pretix/base/channels.py:175
|
||||
msgid ""
|
||||
"API sales channels come with no built-in functionality, but may be used for "
|
||||
"custom integrations."
|
||||
msgstr ""
|
||||
"Kanały sprzedaży API nie mają wbudowanych funkcji, ale mogą być używane do "
|
||||
"niestandardowych integracji."
|
||||
|
||||
#: pretix/base/context.py:45
|
||||
#, python-brace-format
|
||||
@@ -4041,10 +4043,8 @@ msgid "Position"
|
||||
msgstr "Pozycja"
|
||||
|
||||
#: pretix/base/models/discount.py:68
|
||||
#, fuzzy
|
||||
#| msgid "Sales channels"
|
||||
msgid "All supported sales channels"
|
||||
msgstr "Kanały sprzedaży"
|
||||
msgstr "Wszystkie obsługiwane kanały sprzedaży"
|
||||
|
||||
#: pretix/base/models/discount.py:89
|
||||
msgid "Event series handling"
|
||||
@@ -4257,10 +4257,8 @@ msgid "Seating plan"
|
||||
msgstr "Plan miejsc"
|
||||
|
||||
#: pretix/base/models/event.py:639 pretix/base/models/items.py:618
|
||||
#, fuzzy
|
||||
#| msgid "Sales channels"
|
||||
msgid "Sell on all sales channels"
|
||||
msgstr "Kanały sprzedaży"
|
||||
msgstr "Sprzedawaj we wszystkich kanałach sprzedaży"
|
||||
|
||||
#: pretix/base/models/event.py:644 pretix/base/models/items.py:623
|
||||
#: pretix/base/models/items.py:1170 pretix/base/payment.py:417
|
||||
@@ -4570,9 +4568,6 @@ msgid "{category} (Add-On products)"
|
||||
msgstr "{category} (Produkty dodatkowe)"
|
||||
|
||||
#: pretix/base/models/items.py:128
|
||||
#, fuzzy
|
||||
#| msgctxt "checkoutflow"
|
||||
#| msgid "Add-on products"
|
||||
msgid "Add-On products"
|
||||
msgstr "Produkty dodatkowe"
|
||||
|
||||
@@ -4859,11 +4854,8 @@ msgstr ""
|
||||
"przeceny. Ustawienie kosmetyczne bez wzgędlu na faktyczną cenę sprzedaży."
|
||||
|
||||
#: pretix/base/models/items.py:624
|
||||
#, fuzzy
|
||||
#| msgid "Only sell tickets for this event on the following sales channels."
|
||||
msgid "Only sell tickets for this product on the selected sales channels."
|
||||
msgstr ""
|
||||
"Sprzedaj bilety tylko na to wydarzenie na następujących kanałach sprzedaży."
|
||||
msgstr "Sprzedaj bilety na ten produkt tylko w wybranych kanałach sprzedaży."
|
||||
|
||||
#: pretix/base/models/items.py:629
|
||||
msgid ""
|
||||
@@ -5114,6 +5106,8 @@ msgstr "Ten wariant nie będzie sprzedawany po podanej dacie."
|
||||
#: pretix/base/models/items.py:1165
|
||||
msgid "Sell on all sales channels the product is sold on"
|
||||
msgstr ""
|
||||
"Sprzedaj we wszystkich kanałach sprzedaży, w których sprzedawany jest ten "
|
||||
"produkt."
|
||||
|
||||
#: pretix/base/models/items.py:1171
|
||||
msgid ""
|
||||
@@ -6053,9 +6047,6 @@ msgstr "Zaproszenie do zespołu '{team}' dla '{email}'"
|
||||
|
||||
#: pretix/base/models/organizer.py:538
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channels.html:23
|
||||
#, fuzzy
|
||||
#| msgctxt "reusable_medium"
|
||||
#| msgid "Identifier"
|
||||
msgid "Identifier"
|
||||
msgstr "Identyfikator"
|
||||
|
||||
@@ -12050,6 +12041,8 @@ msgid ""
|
||||
"This sales channel cannot be used properly since the respective plugin is "
|
||||
"not active for this event."
|
||||
msgstr ""
|
||||
"Ten kanał sprzedaży nie może być używany prawidłowo, ponieważ odpowiednia "
|
||||
"wtyczka nie jest aktywna dla tego wydarzenia."
|
||||
|
||||
#: pretix/base/templates/pretixbase/forms/widgets/portrait_image.html:10
|
||||
msgid "Upload photo"
|
||||
@@ -14061,6 +14054,8 @@ msgid ""
|
||||
"You have selected dynamic validity but have not entered a time period. This "
|
||||
"would render the tickets unusable."
|
||||
msgstr ""
|
||||
"Wybrałeś dynamiczną ważność, ale nie wprowadziłeś okresu czasu. Spowoduje "
|
||||
"to, że bilety będą bezużyteczne."
|
||||
|
||||
#: pretix/control/forms/item.py:858
|
||||
#, python-format
|
||||
@@ -14807,10 +14802,8 @@ msgid "The selected organizer has already been invited."
|
||||
msgstr "Wybrany organizator został już zaproszony."
|
||||
|
||||
#: pretix/control/forms/organizer.py:1128
|
||||
#, fuzzy
|
||||
#| msgid "A voucher with this code already exists."
|
||||
msgid "A sales channel with the same identifier already exists."
|
||||
msgstr "Voucher o tym kodzie już istnieje."
|
||||
msgstr "Kanał sprzedaży o tym samym identyfikatorze już istnieje."
|
||||
|
||||
#: pretix/control/forms/renderers.py:56
|
||||
#: pretix/control/templates/pretixcontrol/items/question_edit.html:139
|
||||
@@ -15423,23 +15416,16 @@ msgid "The membership type has been deleted."
|
||||
msgstr "Typ członkostwa został usunięty."
|
||||
|
||||
#: pretix/control/logdisplay.py:360 pretix/control/views/organizer.py:3119
|
||||
#, fuzzy
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "The new date has been created."
|
||||
msgid "The sales channel has been created."
|
||||
msgstr "Nowa data została utworzona."
|
||||
msgstr "Kanał sprzedaży został utworzony."
|
||||
|
||||
#: pretix/control/logdisplay.py:361
|
||||
#, fuzzy
|
||||
#| msgid "The device has been changed."
|
||||
msgid "The sales channel has been changed."
|
||||
msgstr "Urządzenie zostało zmienione."
|
||||
msgstr "Kanał sprzedaży został zmieniony."
|
||||
|
||||
#: pretix/control/logdisplay.py:362
|
||||
#, fuzzy
|
||||
#| msgid "The selected list has been deleted."
|
||||
msgid "The sales channel has been deleted."
|
||||
msgstr "Wybrana lista została usunięta."
|
||||
msgstr "Kanał sprzedaży został usunięty."
|
||||
|
||||
#: pretix/control/logdisplay.py:363
|
||||
msgid "The account has been created."
|
||||
@@ -20190,14 +20176,14 @@ msgstr "Utwórz nową kategorię"
|
||||
#: pretix/control/templates/pretixcontrol/items/index.html:146
|
||||
#: pretix/control/templates/pretixcontrol/organizers/properties.html:54
|
||||
msgid "Move up"
|
||||
msgstr ""
|
||||
msgstr "Przesuń w górę"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/categories.html:45
|
||||
#: pretix/control/templates/pretixcontrol/items/discounts.html:142
|
||||
#: pretix/control/templates/pretixcontrol/items/index.html:147
|
||||
#: pretix/control/templates/pretixcontrol/organizers/properties.html:55
|
||||
msgid "Move down"
|
||||
msgstr ""
|
||||
msgstr "Przesuń w dół"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/categories.html:46
|
||||
#: pretix/control/templates/pretixcontrol/items/discounts.html:145
|
||||
@@ -20207,6 +20193,8 @@ msgid ""
|
||||
"Click and drag this button to reorder. Double click to show buttons for "
|
||||
"reordering."
|
||||
msgstr ""
|
||||
"Kliknij i przeciągnij ten przycisk, aby zmienić kolejność. Kliknij "
|
||||
"dwukrotnie, aby wyświetlić przyciski do zmiany kolejności."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/category.html:27
|
||||
msgid "Category history"
|
||||
@@ -20350,15 +20338,12 @@ msgstr ""
|
||||
"produktu"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/discounts.html:111
|
||||
#, fuzzy
|
||||
#| msgctxt "discount"
|
||||
#| msgid "Condition"
|
||||
msgid "Condition:"
|
||||
msgstr "Stan"
|
||||
msgstr "Stan:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/discounts.html:126
|
||||
msgid "Applies to:"
|
||||
msgstr ""
|
||||
msgstr "Dotyczy:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/fragment_quota_availability.html:3
|
||||
msgid "Closed"
|
||||
@@ -20398,12 +20383,6 @@ msgid "taxes"
|
||||
msgstr "podatki"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/index.html:10
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Below, you find a list of all available products. You can click on a "
|
||||
#| "product name to inspect and change product details. You can also use the "
|
||||
#| "buttons on the right to change the order of products within a give "
|
||||
#| "category."
|
||||
msgid ""
|
||||
"Below, you find a list of all available products. You can click on a product "
|
||||
"name to inspect and change product details. You can also use the buttons on "
|
||||
@@ -20412,8 +20391,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Poniżej znajduje się lista wszystkich dostępnych produktów. Możesz kliknąć "
|
||||
"nazwę produktu, aby sprawdzić i zmienić jego szczegóły. Możesz także użyć "
|
||||
"przycisków po prawej stronie, aby zmienić kolejność produktów w danej "
|
||||
"kategorii."
|
||||
"przycisków po prawej stronie, aby zmienić kolejność produktów lub przenieść "
|
||||
"produkty do innej kategorii."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/index.html:19
|
||||
msgid "You haven't created any products yet."
|
||||
@@ -22479,48 +22458,34 @@ msgstr "Wyszukiwanie zamówień"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_add.html:6
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_add_choice.html:6
|
||||
#, fuzzy
|
||||
#| msgid "Sales channel"
|
||||
msgid "Add sales channel"
|
||||
msgstr "Kanał sprzedaży"
|
||||
msgstr "Dodaj kanał sprzedaży"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_add.html:13
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_edit.html:13
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channels.html:24
|
||||
#, fuzzy
|
||||
#| msgid "Scan type"
|
||||
msgid "Channel type"
|
||||
msgstr "Typ skanowania"
|
||||
msgstr "Typ kanału"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:5
|
||||
#, fuzzy
|
||||
#| msgid "Sales channel"
|
||||
msgid "Delete sales channel:"
|
||||
msgstr "Kanał sprzedaży"
|
||||
msgstr "Usuń kanał sprzedaży:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:10
|
||||
#, fuzzy
|
||||
#| msgid "Are you sure you want to delete the gate?"
|
||||
msgid "Are you sure you want to delete this sales channel?"
|
||||
msgstr "Czy na pewno chcesz usunąć bramkę?"
|
||||
msgstr "Czy na pewno chcesz usunąć ten kanał sprzedaży?"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:15
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "This membership cannot be deleted since it has been used in an order. "
|
||||
#| "Change its end date to the past instead."
|
||||
msgid ""
|
||||
"This sales channel cannot be deleted since it has already been used to sell "
|
||||
"orders or because it is a core element of the system."
|
||||
msgstr ""
|
||||
"Tego członkostwa nie można usunąć, ponieważ zostało użyte w zamówieniu. "
|
||||
"Zamiast tego zmień jego datę końcową na przeszłą."
|
||||
"Tego kanału sprzedaży nie można usunąć, ponieważ został już użyty do "
|
||||
"sprzedaży zamówień lub jest podstawowym elementem systemu."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channel_edit.html:6
|
||||
#, fuzzy
|
||||
#| msgid "Sales channel"
|
||||
msgid "Sales channel:"
|
||||
msgstr "Kanał sprzedaży"
|
||||
msgstr "Kanał sprzedaży:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channels.html:8
|
||||
msgid ""
|
||||
@@ -22528,18 +22493,17 @@ msgid ""
|
||||
"through. This is useful to unlock new revenue streams or to separate revenue "
|
||||
"between different sources for reporting purchases."
|
||||
msgstr ""
|
||||
"Na tej stronie można zarządzać różnymi kanałami sprzedaży biletów. Jest to "
|
||||
"przydatne do odblokowania nowych źródeł przychodów lub rozdzielenia "
|
||||
"przychodów między różne źródła w celu raportowania zakupów."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channels.html:15
|
||||
#, fuzzy
|
||||
#| msgid "Add a new value"
|
||||
msgid "Add a new channel"
|
||||
msgstr "Dodaj nową wartość"
|
||||
msgstr "Dodaj nowy kanał"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channels.html:22
|
||||
#, fuzzy
|
||||
#| msgid "Change"
|
||||
msgid "Channel"
|
||||
msgstr "Zmień"
|
||||
msgstr "Kanał"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:7
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:13
|
||||
@@ -26776,34 +26740,24 @@ msgid "The customer account has been anonymized."
|
||||
msgstr "Konto klienta zostało zanonimizowane."
|
||||
|
||||
#: pretix/control/views/organizer.py:3201
|
||||
#, fuzzy
|
||||
#| msgid "This organizer can not be deleted."
|
||||
msgid "This channel can not be deleted."
|
||||
msgstr "Tego organizatora nie można usunąć."
|
||||
msgstr "Tego kanału nie można usunąć."
|
||||
|
||||
#: pretix/control/views/organizer.py:3206
|
||||
#, fuzzy
|
||||
#| msgid "The selected list has been deleted."
|
||||
msgid "The selected sales channel has been deleted."
|
||||
msgstr "Wybrana lista została usunięta."
|
||||
msgstr "Wybrany kanał sprzedaży został usunięty."
|
||||
|
||||
#: pretix/control/views/organizer.py:3208
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "The team could not be deleted as some constraints (e.g. data created by "
|
||||
#| "plug-ins) do not allow it."
|
||||
msgid ""
|
||||
"The channel could not be deleted as some constraints (e.g. data created by "
|
||||
"plug-ins) did not allow it."
|
||||
msgstr ""
|
||||
"Zespół nie mógł zostać usunięty, ponieważ niektóre ograniczenia (np. dane "
|
||||
"utworzone przez wtyczki) na to nie pozwalają."
|
||||
"Kanał nie mógł zostać usunięty, ponieważ niektóre ograniczenia (np. dane "
|
||||
"utworzone przez wtyczki) na to nie pozwoliły."
|
||||
|
||||
#: pretix/control/views/organizer.py:3232
|
||||
#, fuzzy
|
||||
#| msgid "The order of discounts has been updated."
|
||||
msgid "The order of sales channels has been updated."
|
||||
msgstr "Kolejność rabatów została zaktualizowana."
|
||||
msgstr "Kolejność kanałów sprzedaży została zaktualizowana."
|
||||
|
||||
#: pretix/control/views/pdf.py:83
|
||||
msgid "The uploaded PDF file is too large."
|
||||
@@ -28613,13 +28567,6 @@ msgid "Your PayPal account has been disconnected."
|
||||
msgstr "Twoje konto PayPal zostało odłączone."
|
||||
|
||||
#: pretix/plugins/paypal2/apps.py:40
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Accept payments with your PayPal account. In addition to regular PayPal "
|
||||
#| "payments, you can now also offer payments in a variety of local payment "
|
||||
#| "methods such as giropay, SOFORT, iDEAL and many more to your customers - "
|
||||
#| "they don't even need a PayPal account. PayPal is one of the most popular "
|
||||
#| "payment methods world-wide."
|
||||
msgid ""
|
||||
"Accept payments with your PayPal account. In addition to regular PayPal "
|
||||
"payments, you can now also offer payments in a variety of local payment "
|
||||
@@ -28629,9 +28576,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Akceptuj płatności za pomocą konta PayPal. Oprócz zwykłych płatności PayPal, "
|
||||
"możesz teraz oferować swoim klientom płatności za pomocą różnych lokalnych "
|
||||
"metod płatności, takich jak giropay, SOFORT, iDEAL i wiele innych - nie "
|
||||
"potrzebują oni nawet konta PayPal. PayPal jest jedną z najpopularniejszych "
|
||||
"metod płatności na całym świecie."
|
||||
"metod płatności, takich jak eps, iDEAL i wiele innych - nie potrzebują oni "
|
||||
"nawet konta PayPal. PayPal jest jedną z najpopularniejszych metod płatności "
|
||||
"na całym świecie."
|
||||
|
||||
#: pretix/plugins/paypal2/payment.py:99
|
||||
msgid "PayPal Merchant ID"
|
||||
@@ -28652,14 +28599,6 @@ msgid "Alternative Payment Methods"
|
||||
msgstr "Alternatywne metody płatności"
|
||||
|
||||
#: pretix/plugins/paypal2/payment.py:151
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "In addition to payments through a PayPal account, you can also offer your "
|
||||
#| "customers the option to pay with credit cards and other, local payment "
|
||||
#| "methods such as SOFORT, giropay, iDEAL, and many more - even when they do "
|
||||
#| "not have a PayPal account. Eligible payment methods will be determined "
|
||||
#| "based on the shoppers location. For German merchants, this is the direct "
|
||||
#| "successor of PayPal Plus."
|
||||
msgid ""
|
||||
"In addition to payments through a PayPal account, you can also offer your "
|
||||
"customers the option to pay with credit cards and other, local payment "
|
||||
@@ -28670,10 +28609,10 @@ msgid ""
|
||||
msgstr ""
|
||||
"Oprócz płatności za pośrednictwem konta PayPal, możesz również zaoferować "
|
||||
"swoim klientom możliwość płacenia kartami kredytowymi i innymi lokalnymi "
|
||||
"metodami płatności, takimi jak SOFORT, giropay, iDEAL i wiele innych - nawet "
|
||||
"jeśli nie mają konta PayPal. Kwalifikujące się metody płatności zostaną "
|
||||
"określone na podstawie lokalizacji kupującego. Dla niemieckich sprzedawców "
|
||||
"jest to bezpośredni następca PayPal Plus."
|
||||
"metodami płatności, takimi jak eps, iDEAL i wiele innych - nawet jeśli nie "
|
||||
"mają konta PayPal. Kwalifikujące się metody płatności zostaną określone na "
|
||||
"podstawie lokalizacji kupującego. Dla niemieckich sprzedawców jest to "
|
||||
"bezpośredni następca PayPal Plus."
|
||||
|
||||
#: pretix/plugins/paypal2/payment.py:166
|
||||
msgid "Disable SEPA Direct Debit"
|
||||
@@ -29880,11 +29819,6 @@ msgid "Stripe"
|
||||
msgstr "Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/apps.py:40
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Accept payments via Stripe, a globally popular payment service provider. "
|
||||
#| "Stripe supports payments via credit cards as well as many local payment "
|
||||
#| "methods such as giropay, iDEAL, Alipay,and many more."
|
||||
msgid ""
|
||||
"Accept payments via Stripe, a globally popular payment service provider. "
|
||||
"Stripe supports payments via credit cards as well as many local payment "
|
||||
@@ -33278,6 +33212,9 @@ msgid ""
|
||||
"been added to the waiting list. We will only contact you once a spot opens "
|
||||
"up."
|
||||
msgstr ""
|
||||
"Po dodaniu do listy oczekujących <strong>nie</strong> otrzymasz wiadomość e-"
|
||||
"mail z potwierdzeniem. Skontaktujemy się z Tobą dopiero, gdy zwolni się "
|
||||
"miejsce."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/waitinglist.html:44
|
||||
msgid "Add me to the list"
|
||||
|
||||
+3458
-3058
File diff suppressed because it is too large
Load Diff
@@ -119,6 +119,7 @@ class CheckInListMixin(BaseExporter):
|
||||
choices=[
|
||||
('name', _('Attendee name')),
|
||||
('code', _('Order code')),
|
||||
('order_datetime', _('Order date')),
|
||||
] + ([
|
||||
('name:{}'.format(k), _('Attendee name: {part}').format(part=label))
|
||||
for k, label, w in name_scheme['fields']
|
||||
@@ -229,6 +230,8 @@ class CheckInListMixin(BaseExporter):
|
||||
)
|
||||
elif sort == 'code':
|
||||
qs = qs.order_by(*o, 'order__code')
|
||||
elif sort == 'order_datetime':
|
||||
qs = qs.order_by(*o, '-order__datetime')
|
||||
elif sort.startswith('name:'):
|
||||
part = sort[5:]
|
||||
qs = qs.annotate(
|
||||
@@ -516,6 +519,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
|
||||
headers.append(_('Order time'))
|
||||
headers.append(_('Requires special attention'))
|
||||
headers.append(_('Comment'))
|
||||
headers.append(_('Check-in text'))
|
||||
headers.append(_('Seat ID'))
|
||||
headers.append(_('Seat name'))
|
||||
headers.append(_('Seat zone'))
|
||||
@@ -623,6 +627,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
|
||||
row.append(op.order.datetime.astimezone(self.event.timezone).strftime('%H:%M:%S'))
|
||||
row.append(_('Yes') if op.require_checkin_attention else _('No'))
|
||||
row.append(op.order.comment or "")
|
||||
row.append("\n".join(text for text in [op.order.checkin_text, op.item.checkin_text] if text))
|
||||
|
||||
if op.seat:
|
||||
row += [
|
||||
|
||||
@@ -949,6 +949,9 @@ class PaypalMethod(BasePaymentProvider):
|
||||
}
|
||||
})
|
||||
response = self.client.execute(req)
|
||||
except KeyError:
|
||||
raise PaymentException(_('Refunding the amount via PayPal failed: The original payment does not contain '
|
||||
'the required information to issue an automated refund.'))
|
||||
except IOError as e:
|
||||
refund.order.log_action('pretix.event.order.refund.failed', {
|
||||
'local_id': refund.local_id,
|
||||
|
||||
@@ -163,7 +163,7 @@ def signal_process_response(sender, request: HttpRequest, response: HttpResponse
|
||||
# 'frame-src': ['https://www.paypal.com', 'https://www.sandbox.paypal.com', "'nonce-{}'".format(_nonce(request))],
|
||||
'frame-src': ['https:', "'nonce-{}'".format(_nonce(request))],
|
||||
'connect-src': ['https://www.paypal.com', 'https://www.sandbox.paypal.com'], # Or not - seems to only affect PayPal logging...
|
||||
'img-src': ['https://t.paypal.com'],
|
||||
'img-src': ['https://t.paypal.com', 'https://www.paypalobjects.com'],
|
||||
'style-src': ["'unsafe-inline'"] # PayPal does not comply with our nonce unfortunately, see Z#23113213
|
||||
}
|
||||
|
||||
|
||||
@@ -1585,7 +1585,7 @@ class StripeBancontact(StripeRedirectWithAccountNamePaymentIntentMethod):
|
||||
return super().payment_presale_render(payment)
|
||||
|
||||
|
||||
class StripeSofort(StripeMethod):
|
||||
class StripeSofort(StripeRedirectMethod):
|
||||
identifier = 'stripe_sofort'
|
||||
verbose_name = _('SOFORT via Stripe')
|
||||
public_name = _('SOFORT (instant bank transfer)')
|
||||
|
||||
@@ -85,7 +85,7 @@ from pretix.presale.forms.customer import AuthenticationForm, RegistrationForm
|
||||
from pretix.presale.signals import (
|
||||
checkout_all_optional, checkout_confirm_messages, checkout_flow_steps,
|
||||
contact_form_fields, contact_form_fields_overrides,
|
||||
order_meta_from_request, question_form_fields,
|
||||
order_api_meta_from_request, order_meta_from_request, question_form_fields,
|
||||
question_form_fields_overrides,
|
||||
)
|
||||
from pretix.presale.utils import customer_login
|
||||
@@ -1544,11 +1544,14 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
str(m) for m in self.confirm_messages.values()
|
||||
]
|
||||
}
|
||||
api_meta = {}
|
||||
unlock_hashes = request.session.get('pretix_unlock_hashes', [])
|
||||
if unlock_hashes:
|
||||
meta_info['unlock_hashes'] = unlock_hashes
|
||||
for receiver, response in order_meta_from_request.send(sender=request.event, request=request):
|
||||
meta_info.update(response)
|
||||
for receiver, response in order_api_meta_from_request.send(sender=request.event, request=request):
|
||||
api_meta.update(response)
|
||||
|
||||
return self.do(
|
||||
self.request.event.id,
|
||||
@@ -1562,6 +1565,7 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
shown_total=self.cart_session.get('shown_total'),
|
||||
customer=self.cart_session.get('customer'),
|
||||
override_now_dt=time_machine_now(default=None),
|
||||
api_meta=api_meta,
|
||||
)
|
||||
|
||||
def get_success_message(self, value):
|
||||
|
||||
@@ -174,3 +174,11 @@ class CheckoutFieldRenderer(FieldRenderer):
|
||||
else:
|
||||
attrs = ''
|
||||
return '<div class="{klass}"{attrs}>{html}</div>'.format(klass=self.get_form_group_class(), html=html, attrs=attrs)
|
||||
|
||||
def wrap_widget(self, html):
|
||||
if isinstance(self.widget, CheckboxInput):
|
||||
css_class = "checkbox"
|
||||
if self.field.field.disabled:
|
||||
css_class += " disabled"
|
||||
html = f'<div class="{css_class}">{html}</div>'
|
||||
return html
|
||||
|
||||
@@ -84,6 +84,7 @@ seatingframe_html_head = EventPluginSignal()
|
||||
"""
|
||||
Arguments: ``request``
|
||||
|
||||
**Temporary workaround, might be removed again later.**
|
||||
This signal allows you to put code inside the HTML ``<head>`` tag
|
||||
of the seatingframe page in the frontend. You will get the request as the keyword argument
|
||||
``request`` and are expected to return plain HTML.
|
||||
@@ -169,6 +170,17 @@ You will receive the request triggering the order creation as the ``request`` ke
|
||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
order_api_meta_from_request = EventPluginSignal()
|
||||
"""
|
||||
Arguments: ``request``
|
||||
|
||||
This signal is sent before an order is created through the pretixpresale frontend. It allows you
|
||||
to return a dictionary that will be merged in the api_meta attribute of the order.
|
||||
You will receive the request triggering the order creation as the ``request`` keyword argument.
|
||||
|
||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
checkout_confirm_page_content = EventPluginSignal()
|
||||
"""
|
||||
Arguments: ``request``
|
||||
|
||||
@@ -151,7 +151,7 @@ def get_grouped_items(event, *, channel: SalesChannel, subevent=None, voucher=No
|
||||
),
|
||||
).filter(
|
||||
variation_q,
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=channel),
|
||||
active=True,
|
||||
quotas__isnull=False,
|
||||
subevent_disabled=False
|
||||
@@ -685,7 +685,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(
|
||||
self.request.sales_channel.identifier,
|
||||
self.request.sales_channel,
|
||||
voucher,
|
||||
).using(settings.DATABASE_REPLICA),
|
||||
self.request
|
||||
@@ -744,7 +744,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(
|
||||
self.request.sales_channel.identifier,
|
||||
self.request.sales_channel,
|
||||
voucher=voucher,
|
||||
).using(settings.DATABASE_REPLICA),
|
||||
self.request
|
||||
@@ -793,7 +793,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
context['subevent_list'] = self.request.event.subevents_sorted(
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(
|
||||
self.request.sales_channel.identifier,
|
||||
self.request.sales_channel,
|
||||
voucher=voucher,
|
||||
).using(settings.DATABASE_REPLICA),
|
||||
self.request
|
||||
|
||||
@@ -179,7 +179,7 @@ class TicketPageMixin:
|
||||
can_download = can_download and self.order.ticket_download_available
|
||||
ctx['download_email_required'] = can_download and (
|
||||
self.request.event.settings.ticket_download_require_validated_email and
|
||||
self.order.sales_channel == 'web' and
|
||||
self.order.sales_channel.type == 'web' and
|
||||
not self.order.email_known_to_work
|
||||
)
|
||||
ctx['can_download'] = can_download and not ctx['download_email_required']
|
||||
@@ -1106,7 +1106,7 @@ class OrderDownloadMixin:
|
||||
|
||||
if (
|
||||
self.request.event.settings.ticket_download_require_validated_email and
|
||||
self.order.sales_channel == 'web' and
|
||||
self.order.sales_channel.type == 'web' and
|
||||
not self.order.email_known_to_work
|
||||
):
|
||||
return self.error(OrderError(_('Please click the link we sent you via email to download your tickets.')))
|
||||
|
||||
@@ -185,7 +185,7 @@ class EventListMixin:
|
||||
def _get_event_list_queryset(self):
|
||||
query = Q(is_public=True) & Q(live=True)
|
||||
qs = self.request.organizer.events.using(settings.DATABASE_REPLICA).filter(query)
|
||||
qs = qs.filter(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier))
|
||||
qs = qs.filter(Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel))
|
||||
qs = qs.annotate(
|
||||
min_from=Min('subevents__date_from'),
|
||||
min_to=Min('subevents__date_to'),
|
||||
@@ -213,7 +213,7 @@ class EventListMixin:
|
||||
).order_by('order_from')
|
||||
qs = Event.annotated(filter_qs_by_attr(
|
||||
qs, self.request, match_subevents_with_conditions=Q(active=True) & Q(is_public=True) & date_q
|
||||
))
|
||||
), self.request.sales_channel)
|
||||
return qs
|
||||
|
||||
def _set_month_to_next_subevent(self):
|
||||
@@ -724,10 +724,10 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
ctx['has_before'], ctx['has_after'] = has_before_after(
|
||||
self.request.organizer.events.filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
),
|
||||
SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) | Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__all_sales_channels=True) | Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
@@ -746,14 +746,14 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
def _events_by_day(self, before, after):
|
||||
ebd = defaultdict(list)
|
||||
timezones = set()
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using(
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, self.request.sales_channel).using(
|
||||
settings.DATABASE_REPLICA
|
||||
).filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
), before, after, ebd, timezones)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
@@ -768,7 +768,7 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
)
|
||||
)
|
||||
)
|
||||
)), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
|
||||
), self.request.sales_channel), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
|
||||
self._multiple_timezones = len(timezones) > 1
|
||||
return ebd
|
||||
|
||||
@@ -807,11 +807,11 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
ctx['has_before'], ctx['has_after'] = has_before_after(
|
||||
self.request.organizer.events.filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
),
|
||||
SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
@@ -842,14 +842,14 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
def _events_by_day(self, before, after):
|
||||
ebd = defaultdict(list)
|
||||
timezones = set()
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using(
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, self.request.sales_channel).using(
|
||||
settings.DATABASE_REPLICA
|
||||
).filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
), before, after, ebd, timezones)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
@@ -864,7 +864,7 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
)
|
||||
)
|
||||
)
|
||||
)), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
|
||||
), self.request.sales_channel), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
|
||||
self._multiple_timezones = len(timezones) > 1
|
||||
return ebd
|
||||
|
||||
@@ -946,11 +946,11 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
ctx['has_before'], ctx['has_after'] = has_before_after(
|
||||
self.request.organizer.events.filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
),
|
||||
SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
@@ -1194,14 +1194,14 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
def _events_by_day(self, before, after):
|
||||
ebd = defaultdict(list)
|
||||
timezones = set()
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using(
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, self.request.sales_channel).using(
|
||||
settings.DATABASE_REPLICA
|
||||
).filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
), before, after, ebd, timezones)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
@@ -1216,7 +1216,7 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
)
|
||||
)
|
||||
)
|
||||
)), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
|
||||
), self.request.sales_channel), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
|
||||
self._multiple_timezones = len(timezones) > 1
|
||||
return ebd
|
||||
|
||||
@@ -1229,7 +1229,7 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
|
||||
filter_qs_by_attr(
|
||||
self.request.organizer.events.filter(
|
||||
Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
is_public=True,
|
||||
live=True,
|
||||
has_subevents=False,
|
||||
@@ -1250,7 +1250,7 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
|
||||
SubEvent.objects.filter(
|
||||
Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff),
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
|
||||
@@ -545,9 +545,9 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
if hasattr(self.request, 'event'):
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated('web').filter(
|
||||
self.request.event.subevents_annotated(self.request.sales_channel).filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Q(event__limit_sales_channels=self.request.sales_channel),
|
||||
), self.request
|
||||
),
|
||||
limit_before, after, ebd, set(), self.request.event,
|
||||
@@ -558,8 +558,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
add_events_for_days(
|
||||
self.request,
|
||||
filter_qs_by_attr(
|
||||
Event.annotated(self.request.organizer.events, 'web').filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
Event.annotated(self.request.organizer.events, self.request.sales_channel).filter(
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
|
||||
), self.request
|
||||
),
|
||||
limit_before, after, ebd, timezones
|
||||
@@ -572,7 +572,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
event__live=True,
|
||||
).prefetch_related(
|
||||
'event___settings_objects', 'event__organizer___settings_objects'
|
||||
)), self.request), limit_before, after, ebd, timezones)
|
||||
), self.request.sales_channel), self.request), limit_before, after, ebd, timezones)
|
||||
|
||||
data['weeks'] = weeks_for_template(ebd, self.year, self.month)
|
||||
for w in data['weeks']:
|
||||
@@ -605,7 +605,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
ebd = defaultdict(list)
|
||||
if hasattr(self.request, 'event'):
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(self.request.event.subevents_annotated('web'), self.request),
|
||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel), self.request),
|
||||
limit_before, after, ebd, set(), self.request.event,
|
||||
kwargs.get('cart_namespace')
|
||||
)
|
||||
@@ -613,7 +613,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
timezones = set()
|
||||
add_events_for_days(
|
||||
self.request,
|
||||
filter_qs_by_attr(Event.annotated(self.request.organizer.events, 'web'), self.request),
|
||||
filter_qs_by_attr(Event.annotated(self.request.organizer.events, self.request.sales_channel), self.request),
|
||||
limit_before, after, ebd, timezones
|
||||
)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
@@ -622,7 +622,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
event__live=True,
|
||||
).prefetch_related(
|
||||
'event___settings_objects', 'event__organizer___settings_objects'
|
||||
)), self.request), limit_before, after, ebd, timezones)
|
||||
), self.request.sales_channel), self.request), limit_before, after, ebd, timezones)
|
||||
|
||||
data['days'] = days_for_template(ebd, week)
|
||||
for d in data['days']:
|
||||
@@ -632,7 +632,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
limit = 50
|
||||
if hasattr(self.request, 'event'):
|
||||
evs = filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(self.request.sales_channel.identifier),
|
||||
self.request.event.subevents_annotated(self.request.sales_channel),
|
||||
self.request,
|
||||
match_subevents_with_conditions=(
|
||||
Q(Q(date_to__isnull=True) & Q(date_from__gte=now() - timedelta(hours=24)))
|
||||
|
||||
+773
-767
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/preset-env": "^7.24.6",
|
||||
"@babel/preset-env": "^7.24.7",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"vue": "^2.7.16",
|
||||
|
||||
@@ -195,7 +195,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
}
|
||||
.alert-danger::before {
|
||||
background-color: $state-danger-border;
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2036%2036'%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%3E%3Cpath%20d='M12.14%204.62h11.64l8.24%208.24V23.4l-8.24%208.24H12.14L3.9%2023.39V12.86l8.24-8.24Z'%20fill='%23fff'/%3E%3Cpath%20d='M24.74%2022.6c0-.28-.11-.56-.31-.76l-3.27-3.27%203.27-3.27a1.08%201.08%200%200%200%200-1.52l-1.51-1.5a1.08%201.08%200%200%200-1.52%200l-3.27%203.26-3.27-3.27a1.08%201.08%200%200%200-1.52%200l-1.5%201.51a1.08%201.08%200%200%200%200%201.52l3.26%203.27-3.27%203.27a1.08%201.08%200%200%200%200%201.52l1.51%201.51a1.08%201.08%200%200%200%201.52%200l3.27-3.27%203.27%203.27a1.08%201.08%200%200%200%201.52%200l1.51-1.51c.2-.2.31-.48.31-.76Z'%20fill='#{url-friendly-colour($state-danger-text)}'/%3E%3C/svg%3E%0A");
|
||||
background-image: url('data:image/svg+xml,<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xml:space="preserve"><path d="M12.14 4.62h11.64l8.24 8.24V23.4l-8.24 8.24H12.14L3.9 23.39V12.86l8.24-8.24Zm12.6 17.98c0-.28-.11-.56-.31-.76l-3.27-3.27 3.27-3.27a1.085 1.085 0 0 0 0-1.52l-1.51-1.5a1.085 1.085 0 0 0-1.52 0l-3.27 3.26-3.27-3.27a1.085 1.085 0 0 0-1.52 0l-1.5 1.51a1.085 1.085 0 0 0 0 1.52l3.26 3.27-3.27 3.27a1.085 1.085 0 0 0 0 1.52l1.51 1.51a1.085 1.085 0 0 0 1.52 0l3.27-3.27 3.27 3.27a1.085 1.085 0 0 0 1.52 0l1.51-1.51c.2-.2.31-.48.31-.76Z" style="fill:%23fff"/></svg>');
|
||||
}
|
||||
.alert-primary::before {
|
||||
background: $brand-primary !important;
|
||||
|
||||
@@ -781,7 +781,7 @@ function setup_basics(el) {
|
||||
scrollTarget.id = "panel_" + $("input", scrollTarget).attr("id");
|
||||
}
|
||||
} else {
|
||||
label = $("label", this).first().text();
|
||||
label = $("label", this).first().contents().filter(function () { return this.nodeType != Node.ELEMENT_NODE || !this.classList.contains("optional") }).text();
|
||||
description = $(".help-block", this).first().text();
|
||||
scrollTarget = $(":input", this).get(0);
|
||||
}
|
||||
|
||||
@@ -767,9 +767,11 @@ h1 .label {
|
||||
.plugin-container {
|
||||
flex-basis: 100%;
|
||||
flex-shrink: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
padding-top: 15px;
|
||||
}
|
||||
.plugin-container:not(.featured-plugin) + .plugin-container {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@@ -380,23 +380,28 @@ $(function () {
|
||||
" #id_city, #id_country, #id_state").change(function () {
|
||||
if (copy_to_first_ticket) {
|
||||
var $first_ticket_form = $(".questions-form").first().find("[data-addonidx=0]");
|
||||
$first_ticket_form.find("input[id*=attendee_email]").val($("#id_email").val());
|
||||
$first_ticket_form.find("input[id$=company]").val($("#id_company").val());
|
||||
$first_ticket_form.find("textarea[id$=street]").val($("#id_street").val());
|
||||
$first_ticket_form.find("input[id$=zipcode]").val($("#id_zipcode").val());
|
||||
$first_ticket_form.find("input[id$=city]").val($("#id_city").val());
|
||||
|
||||
$first_ticket_form.find("select[id$=state]").val($("#id_state").val());
|
||||
if ($first_ticket_form.find("select[id$=country]").val() !== $("#id_country").val()) {
|
||||
$first_ticket_form.find("select[id$=country]").val($("#id_country").val()).trigger('change');
|
||||
$first_ticket_form.find("[id$=" + this.id.substring(3) + "]").val(this.value);
|
||||
if (this.placeholder) {
|
||||
$first_ticket_form.find("[placeholder='" + this.placeholder + "']").val(this.value);
|
||||
}
|
||||
var label = $("label[for=" + this.id +"]").first().contents().filter(function () {
|
||||
return this.nodeType != Node.ELEMENT_NODE || !this.classList.contains("sr-only");
|
||||
}).text().trim();
|
||||
if (label) {
|
||||
// match to placeholder and label
|
||||
$first_ticket_form.find("[placeholder='" + label + "']").val(this.value);
|
||||
var v = this.value;
|
||||
$first_ticket_form.find("label").each(function() {
|
||||
var text = $(this).first().contents().filter(function () {
|
||||
return this.nodeType != Node.ELEMENT_NODE || !this.classList.contains("sr-only");
|
||||
}).text().trim();
|
||||
if (text == label) {
|
||||
$("#" + this.getAttribute("for")).val(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
$first_ticket_form.find("[id*=attendee_name_parts]").each(function () {
|
||||
var parts = $(this).attr("id").split("_");
|
||||
var num = parts[parts.length - 1];
|
||||
$(this).val($("#id_name_parts_" + num).val());
|
||||
});
|
||||
}
|
||||
});
|
||||
}).trigger("change");
|
||||
attendee_address_fields.change(function () {
|
||||
copy_to_first_ticket = false;
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ filterwarnings =
|
||||
ignore::DeprecationWarning:django
|
||||
ignore::DeprecationWarning:cgi
|
||||
ignore::DeprecationWarning:vat_moss
|
||||
ignore::cryptography.utils.CryptographyDeprecationWarning:pypdf
|
||||
ignore:.*ast.NameConstant.*:DeprecationWarning:reportlab
|
||||
ignore:.*utcnow.*:DeprecationWarning:
|
||||
ignore:.*PyType_Spec.*:DeprecationWarning:
|
||||
|
||||
@@ -1381,3 +1381,18 @@ def test_checkin_pdf_data_requires_permission(token_client, event, team, organiz
|
||||
organizer.slug, event.slug, clist_all.pk
|
||||
))
|
||||
assert not resp.data['results'][0].get('pdf_data')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_expand(token_client, organizer, event, clist, clist_all, item, other_item, order, django_assert_max_num_queries):
|
||||
with scopes_disabled():
|
||||
op = order.positions.first()
|
||||
var1 = item.variations.create(value="XS")
|
||||
op.variation = var1
|
||||
op.save()
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?search=z3fsn8jyu&expand=variation'.format(
|
||||
organizer.slug, event.slug, clist_all.pk
|
||||
))
|
||||
assert resp.status_code == 200
|
||||
assert 'value' in resp.data['results'][0]['variation']
|
||||
|
||||
@@ -763,6 +763,50 @@ def test_event_update(token_client, organizer, event, item, meta_prop):
|
||||
assert cnt == event.all_logentries().count()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_update_plugins_validation(token_client, organizer, event, item, meta_prop):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"plugins": ["pretix.plugins.paypal2", "unknown"]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"plugins": ["Unknown plugin: 'unknown'."]}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"plugins": ["pretix.plugins.paypal2", "tests.testdummyhidden"]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"plugins": ["Unknown plugin: 'tests.testdummyhidden'."]}
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"plugins": ["pretix.plugins.paypal2", "tests.testdummyrestricted"]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"plugins": ["Restricted plugin: 'tests.testdummyrestricted'."]}
|
||||
|
||||
organizer.settings.allowed_restricted_plugins = ["tests.testdummyrestricted"]
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"plugins": ["pretix.plugins.paypal2", "tests.testdummyrestricted"]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_test_mode(token_client, organizer, event):
|
||||
resp = token_client.patch(
|
||||
|
||||
@@ -86,6 +86,18 @@ def test_giftcard_list(token_client, organizer, event, giftcard, other_giftcard)
|
||||
assert resp.status_code == 200
|
||||
assert 2 == len(resp.data['results'])
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?expired=false'.format(organizer.slug))
|
||||
assert 1 == len(resp.data['results'])
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?expired=true'.format(organizer.slug))
|
||||
assert 0 == len(resp.data['results'])
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=23.00'.format(organizer.slug))
|
||||
assert 1 == len(resp.data['results'])
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=23'.format(organizer.slug))
|
||||
assert 1 == len(resp.data['results'])
|
||||
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=24'.format(organizer.slug))
|
||||
assert 0 == len(resp.data['results'])
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_giftcard_detail(token_client, organizer, event, giftcard):
|
||||
|
||||
@@ -370,6 +370,13 @@ def test_item_list(token_client, organizer, event, team, item):
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/?search=Budget'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/?search=Free'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_item_detail(token_client, organizer, event, team, item):
|
||||
@@ -590,7 +597,28 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego
|
||||
"meta_data": {
|
||||
"day": "Wednesday",
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": {
|
||||
"de": "web",
|
||||
"en": "web"
|
||||
},
|
||||
"active": True,
|
||||
"require_approval": True,
|
||||
"checkin_attention": False,
|
||||
"checkin_text": None,
|
||||
"require_membership": False,
|
||||
"require_membership_hidden": False,
|
||||
"require_membership_types": [],
|
||||
"description": None,
|
||||
"position": 0,
|
||||
"default_price": None,
|
||||
"sales_channels": ["web"],
|
||||
"price": "23.00",
|
||||
"meta_data": {
|
||||
"day": "Wednesday",
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
format='json'
|
||||
@@ -604,6 +632,8 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego
|
||||
assert new_item.variations.first().all_sales_channels is True
|
||||
assert not new_item.variations.first().limit_sales_channels.exists()
|
||||
assert new_item.variations.first().meta_data == {"day": "Wednesday"}
|
||||
assert new_item.variations.last().all_sales_channels is False
|
||||
assert new_item.variations.last().limit_sales_channels.exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -1389,6 +1419,21 @@ def test_variations_list(token_client, organizer, event, item, variation):
|
||||
assert res['position'] == resp.data['results'][0]['position']
|
||||
assert res['price'] == resp.data['results'][0]['price']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?active=true'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res['value'] == resp.data['results'][0]['value']
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/variations/?active=false'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?search=Child'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res['value'] == resp.data['results'][0]['value']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?search=Incorrect'.format(organizer.slug, event.slug, item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_variations_detail(token_client, organizer, event, item, variation):
|
||||
|
||||
@@ -255,6 +255,9 @@ def test_order_update_allowed_fields(token_client, organizer, event, order):
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'comment': 'Here is a comment',
|
||||
'api_meta': {
|
||||
'test': 1
|
||||
},
|
||||
'valid_if_pending': True,
|
||||
'custom_followup_at': '2021-06-12',
|
||||
'checkin_attention': True,
|
||||
@@ -280,6 +283,9 @@ def test_order_update_allowed_fields(token_client, organizer, event, order):
|
||||
assert resp.status_code == 200
|
||||
order.refresh_from_db()
|
||||
assert order.comment == 'Here is a comment'
|
||||
assert order.api_meta == {
|
||||
'test': 1
|
||||
}
|
||||
assert order.custom_followup_at.isoformat() == '2021-06-12'
|
||||
assert order.checkin_attention
|
||||
assert order.checkin_text == 'foobar'
|
||||
|
||||
@@ -232,6 +232,9 @@ def test_order_create(token_client, organizer, event, item, quota, question):
|
||||
with scopes_disabled():
|
||||
customer = organizer.customers.create()
|
||||
res['customer'] = customer.identifier
|
||||
res['api_meta'] = {
|
||||
'test': 1
|
||||
}
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
@@ -251,6 +254,9 @@ def test_order_create(token_client, organizer, event, item, quota, question):
|
||||
assert o.valid_if_pending
|
||||
assert o.expires > now()
|
||||
assert not o.testmode
|
||||
assert o.api_meta == {
|
||||
'test': 1
|
||||
}
|
||||
|
||||
with scopes_disabled():
|
||||
p = o.payments.first()
|
||||
@@ -421,6 +427,7 @@ def test_order_create_simulate(token_client, organizer, event, item, quota, ques
|
||||
],
|
||||
'total': '21.75',
|
||||
'comment': '',
|
||||
'api_meta': {},
|
||||
"custom_followup_at": None,
|
||||
'invoice_address': {
|
||||
'is_business': False,
|
||||
|
||||
@@ -291,6 +291,7 @@ TEST_ORDER_RES = {
|
||||
"payment_provider": "banktransfer",
|
||||
"total": "23.00",
|
||||
"comment": "",
|
||||
"api_meta": {},
|
||||
"custom_followup_at": None,
|
||||
"checkin_attention": False,
|
||||
"checkin_text": None,
|
||||
@@ -414,6 +415,16 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi
|
||||
'/api/v1/organizers/{}/events/{}/orders/?email=foo@example.org'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=banktransfer'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=manual'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=web'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=bar'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=en'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=de'.format(organizer.slug, event.slug))
|
||||
@@ -434,6 +445,36 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
||||
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
||||
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
||||
organizer.slug, event.slug,
|
||||
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_positions=false'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.data['results'][0]['positions']) == 1
|
||||
|
||||
@@ -60,6 +60,11 @@ def test_hook_list(token_client, organizer, event, webhook):
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
resp = token_client.get('/api/v1/organizers/{}/webhooks/?enabled=true'.format(organizer.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/webhooks/?enabled=false'.format(organizer.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_hook_detail(token_client, organizer, event, webhook):
|
||||
|
||||
@@ -2329,8 +2329,8 @@ class EventTest(TestCase):
|
||||
item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=False)
|
||||
q.items.add(item)
|
||||
q.items.add(item2)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, 'foo').first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, self.organizer.sales_channels.get(identifier="bar")).first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_product_inactive(self):
|
||||
@@ -2341,7 +2341,7 @@ class EventTest(TestCase):
|
||||
q = Quota.objects.create(event=event, name='Quota', size=2)
|
||||
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=False)
|
||||
q.items.add(item)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_product_hidden_by_voucher(self):
|
||||
@@ -2354,16 +2354,16 @@ class EventTest(TestCase):
|
||||
q.items.add(item)
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='a', item=item, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='b', item=item, show_hidden_items=False)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == []
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='c', show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='d', quota=q, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0)
|
||||
var = item2.variations.create(item=item2, value='Test', hide_without_voucher=True)
|
||||
@@ -2373,13 +2373,13 @@ class EventTest(TestCase):
|
||||
q.variations.add(var)
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='e', item=item2, variation=var, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='f', item=item2, variation=var2, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == []
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='g', quota=q, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_product_addon(self):
|
||||
@@ -2395,7 +2395,7 @@ class EventTest(TestCase):
|
||||
item.category = cat
|
||||
item.save()
|
||||
q.items.add(item)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_product_unavailable(self):
|
||||
@@ -2407,7 +2407,7 @@ class EventTest(TestCase):
|
||||
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=True,
|
||||
available_until=now() - timedelta(days=1))
|
||||
q.items.add(item)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_variation_not_in_quota(self):
|
||||
@@ -2419,7 +2419,7 @@ class EventTest(TestCase):
|
||||
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=True)
|
||||
item.variations.create(value="foo")
|
||||
q.items.add(item)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_variation(self):
|
||||
@@ -2434,29 +2434,29 @@ class EventTest(TestCase):
|
||||
v.limit_sales_channels.add(self.organizer.sales_channels.get(identifier="web"))
|
||||
q.items.add(item)
|
||||
q.variations.add(v)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == [q]
|
||||
item.available_until = now() - timedelta(days=1)
|
||||
item.save()
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
item.available_until = None
|
||||
item.available_from = now() + timedelta(days=1)
|
||||
item.save()
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
item.available_until = None
|
||||
item.available_from = None
|
||||
item.active = False
|
||||
item.save()
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
item.active = True
|
||||
item.save()
|
||||
assert Event.annotated(Event.objects).first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, 'foo').first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == [q]
|
||||
assert Event.annotated(Event.objects, self.organizer.sales_channels.get(identifier="bar")).first().active_quotas == []
|
||||
v.active = False
|
||||
v.save()
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
item.hide_without_voucher = True
|
||||
item.save()
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
assert Event.annotated(Event.objects, 'web').first().active_quotas == []
|
||||
|
||||
|
||||
class SubEventTest(TestCase):
|
||||
@@ -2502,8 +2502,10 @@ class SubEventTest(TestCase):
|
||||
all_sales_channels=False)
|
||||
item.limit_sales_channels.add(self.organizer.sales_channels.get(identifier="web"))
|
||||
q.items.add(item)
|
||||
assert SubEvent.annotated(SubEvent.objects).first().active_quotas == [q]
|
||||
assert SubEvent.annotated(SubEvent.objects, 'foo').first().active_quotas == []
|
||||
assert SubEvent.annotated(SubEvent.objects, 'web').first().active_quotas == [q]
|
||||
assert SubEvent.annotated(SubEvent.objects, 'bar').first().active_quotas == []
|
||||
assert SubEvent.annotated(SubEvent.objects, self.organizer.sales_channels.get(identifier="web")).first().active_quotas == [q]
|
||||
assert SubEvent.annotated(SubEvent.objects, self.organizer.sales_channels.get(identifier="bar")).first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_no_interference(self):
|
||||
@@ -2514,8 +2516,8 @@ class SubEventTest(TestCase):
|
||||
subevent=se2)
|
||||
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True)
|
||||
q.items.add(item)
|
||||
assert SubEvent.annotated(SubEvent.objects).filter(pk=self.se.pk).first().active_quotas == []
|
||||
assert SubEvent.annotated(SubEvent.objects).filter(pk=se2.pk).first().active_quotas == [q]
|
||||
assert SubEvent.annotated(SubEvent.objects, 'web').filter(pk=self.se.pk).first().active_quotas == []
|
||||
assert SubEvent.annotated(SubEvent.objects, 'web').filter(pk=se2.pk).first().active_quotas == [q]
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_best_availability(self):
|
||||
@@ -2540,7 +2542,7 @@ class SubEventTest(TestCase):
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=1,
|
||||
subevent=self.se)
|
||||
q.items.add(item)
|
||||
obj = SubEvent.annotated(SubEvent.objects).first()
|
||||
obj = SubEvent.annotated(SubEvent.objects, 'web').first()
|
||||
assert len(obj.active_quotas) == 1
|
||||
assert obj.best_availability == (Quota.AVAILABILITY_GONE, 0, 1)
|
||||
|
||||
@@ -2548,14 +2550,14 @@ class SubEventTest(TestCase):
|
||||
q2 = Quota.objects.create(event=self.event, name='Quota 2', size=2,
|
||||
subevent=self.se)
|
||||
q2.items.add(item)
|
||||
obj = SubEvent.annotated(SubEvent.objects).first()
|
||||
obj = SubEvent.annotated(SubEvent.objects, 'web').first()
|
||||
assert len(obj.active_quotas) == 2
|
||||
assert obj.best_availability == (Quota.AVAILABILITY_GONE, 0, 1)
|
||||
|
||||
# 2 quotas - 2 items. Higher quota wins since second item is only connected to second quota.
|
||||
item2 = Item.objects.create(event=self.event, name='Regular ticket', default_price=10, active=True)
|
||||
q2.items.add(item2)
|
||||
obj = SubEvent.annotated(SubEvent.objects).first()
|
||||
obj = SubEvent.annotated(SubEvent.objects, 'web').first()
|
||||
assert len(obj.active_quotas) == 2
|
||||
assert obj.best_availability == (Quota.AVAILABILITY_OK, 1, 2)
|
||||
assert obj.best_availability_is_low
|
||||
@@ -2564,7 +2566,7 @@ class SubEventTest(TestCase):
|
||||
q.size = 10
|
||||
q.save()
|
||||
q2.delete()
|
||||
obj = SubEvent.annotated(SubEvent.objects).first()
|
||||
obj = SubEvent.annotated(SubEvent.objects, 'web').first()
|
||||
assert len(obj.active_quotas) == 1
|
||||
assert obj.best_availability == (Quota.AVAILABILITY_OK, 9, 10)
|
||||
assert not obj.best_availability_is_low
|
||||
@@ -2572,7 +2574,7 @@ class SubEventTest(TestCase):
|
||||
# Unlimited quota
|
||||
q.size = None
|
||||
q.save()
|
||||
obj = SubEvent.annotated(SubEvent.objects).first()
|
||||
obj = SubEvent.annotated(SubEvent.objects, 'web').first()
|
||||
assert obj.best_availability == (Quota.AVAILABILITY_OK, None, None)
|
||||
assert not obj.best_availability_is_low
|
||||
|
||||
|
||||
@@ -299,6 +299,8 @@ class EventsTest(SoupTest):
|
||||
doc = self.get_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug))
|
||||
self.assertIn("Stripe", doc.select(".form-plugins")[0].text)
|
||||
self.assertIn("Enable", doc.select("[name=\"plugin:pretix.plugins.stripe\"]")[0].text)
|
||||
assert not doc.select("[name=\"plugin:tests.testdummyrestricted\"]")
|
||||
assert not doc.select("[name=\"plugin:tests.testdummyhidden\"]")
|
||||
|
||||
doc = self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
|
||||
{'plugin:pretix.plugins.stripe': 'enable'})
|
||||
@@ -308,6 +310,23 @@ class EventsTest(SoupTest):
|
||||
{'plugin:pretix.plugins.stripe': 'disable'})
|
||||
self.assertIn("Enable", doc.select("[name=\"plugin:pretix.plugins.stripe\"]")[0].text)
|
||||
|
||||
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
|
||||
{'plugin:tests.testdummyhidden': 'enable'})
|
||||
self.event1.refresh_from_db()
|
||||
assert "testdummyhidden" not in self.event1.plugins
|
||||
|
||||
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
|
||||
{'plugin:tests.testdummyrestricted': 'enable'})
|
||||
self.event1.refresh_from_db()
|
||||
assert "testdummyrestricted" not in self.event1.plugins
|
||||
|
||||
self.orga1.settings.allowed_restricted_plugins = ["tests.testdummyrestricted"]
|
||||
|
||||
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
|
||||
{'plugin:tests.testdummyrestricted': 'enable'})
|
||||
self.event1.refresh_from_db()
|
||||
assert "testdummyrestricted" in self.event1.plugins
|
||||
|
||||
def test_testmode_enable(self):
|
||||
self.event1.testmode = False
|
||||
self.event1.save()
|
||||
|
||||
@@ -91,12 +91,12 @@ def test_csv_simple(event):
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title","Attendee name:
|
||||
First name","Attendee name: Middle name","Attendee name: Family name","Product","Price","Checked in","Checked out","Automatically
|
||||
checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special attention",
|
||||
"Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until","Address","ZIP code",
|
||||
"Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until","Address","ZIP code",
|
||||
"City","Country","State"
|
||||
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
""")
|
||||
|
||||
|
||||
@@ -113,12 +113,12 @@ def test_csv_order_by_name_parts(event): # noqa
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
|
||||
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
|
||||
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
|
||||
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
"Address","ZIP code","City","Country","State"
|
||||
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
""")
|
||||
c = CSVCheckinList(event, organizer=event.organizer)
|
||||
_, _, content = c.render({
|
||||
@@ -131,12 +131,12 @@ def test_csv_order_by_name_parts(event): # noqa
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
|
||||
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
|
||||
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
|
||||
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
"Address","ZIP code","City","Country","State"
|
||||
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
""")
|
||||
|
||||
|
||||
@@ -184,12 +184,12 @@ def test_csv_order_by_inherited_name_parts(event): # noqa
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
|
||||
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
|
||||
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
|
||||
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
"Address","ZIP code","City","Country","State"
|
||||
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
|
||||
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
""")
|
||||
c = CSVCheckinList(event, organizer=event.organizer)
|
||||
_, _, content = c.render({
|
||||
@@ -202,12 +202,12 @@ def test_csv_order_by_inherited_name_parts(event): # noqa
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
|
||||
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
|
||||
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
|
||||
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
"Address","ZIP code","City","Country","State"
|
||||
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
|
||||
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
""")
|
||||
c = CSVCheckinList(event, organizer=event.organizer)
|
||||
_, _, content = c.render({
|
||||
@@ -220,10 +220,55 @@ def test_csv_order_by_inherited_name_parts(event): # noqa
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
|
||||
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
|
||||
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
|
||||
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
|
||||
"Address","ZIP code","City","Country","State"
|
||||
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
|
||||
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","",""
|
||||
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
|
||||
""")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_csv_order_by_orderdatetime(event):
|
||||
order1 = event.orders.first()
|
||||
order1.checkin_text = 'meow'
|
||||
order1.save()
|
||||
order2 = Order.objects.create(
|
||||
code='FOO2', event=event, email='dummy@dummy.test', phone="+498912345678",
|
||||
status=Order.STATUS_PAID,
|
||||
datetime=datetime.datetime(2019, 2, 22, 22, 0, 0, tzinfo=datetime.timezone.utc),
|
||||
expires=now() + datetime.timedelta(days=10),
|
||||
total=33, locale='en', checkin_text='beep',
|
||||
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
||||
)
|
||||
item_ticket = Item.objects.create(event=event, name="Ticket2", default_price=23, admission=True, checkin_text='boop')
|
||||
OrderPosition.objects.create(
|
||||
order=order2,
|
||||
item=item_ticket,
|
||||
variation=None,
|
||||
price=Decimal("23"),
|
||||
attendee_name_parts={"title": "Mx", "given_name": "Alex", "middle_name": "F", "family_name": "Nord"},
|
||||
secret='asdfasdfasdfasdfasdfasdfasfdasdf'
|
||||
)
|
||||
|
||||
c = CSVCheckinList(event, organizer=event.organizer)
|
||||
_, _, content = c.render({
|
||||
'list': event.checkin_lists.first().pk,
|
||||
'secrets': True,
|
||||
'sort': 'order_datetime',
|
||||
'_format': 'default',
|
||||
'questions': []
|
||||
})
|
||||
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title","Attendee name:
|
||||
First name","Attendee name: Middle name","Attendee name: Family name","Product","Price","Checked in","Checked out","Automatically
|
||||
checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special attention",
|
||||
"Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until","Address","ZIP code",
|
||||
"City","Country","State"
|
||||
"FOO2","Mx Alex F Nord","Mx","Alex","F","Nord","Ticket2","23.00","","","No","asdfasdfasdfasdfasdfasdfasfdasdf",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","22:00:00","No","","beep\nboop","","","","","","","","","","","","",""
|
||||
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","meow","","","","","","","","","","","","",""
|
||||
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
|
||||
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","meow","","","","","","","","","","","","",""
|
||||
""")
|
||||
|
||||
@@ -28,6 +28,8 @@ TEST_DIR = os.path.dirname(__file__)
|
||||
TEMPLATES[0]['DIRS'].append(os.path.join(TEST_DIR, 'templates')) # NOQA
|
||||
|
||||
INSTALLED_APPS.append('tests.testdummy') # NOQA
|
||||
INSTALLED_APPS.append('tests.testdummyrestricted') # NOQA
|
||||
INSTALLED_APPS.append('tests.testdummyhidden') # NOQA
|
||||
|
||||
PRETIX_AUTH_BACKENDS = [
|
||||
'pretix.base.auth.NativeAuthBackend',
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TestDummyHiddenApp(AppConfig):
|
||||
name = 'tests.testdummyhidden'
|
||||
verbose_name = 'testdummyhidden'
|
||||
|
||||
class PretixPluginMeta:
|
||||
name = 'testdummyhidden'
|
||||
version = '1.0.0'
|
||||
restricted = True
|
||||
|
||||
def is_available(self, event):
|
||||
return False
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TestDummyRestrictedApp(AppConfig):
|
||||
name = 'tests.testdummyrestricted'
|
||||
verbose_name = 'testdummyrestricted'
|
||||
|
||||
class PretixPluginMeta:
|
||||
name = 'testdummyrestricted'
|
||||
version = '1.0.0'
|
||||
restricted = True
|
||||
Reference in New Issue
Block a user