forked from CGM_Public/pretix_original
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df25ae3c7c | ||
|
|
d686b386e3 | ||
|
|
bdda68c82d | ||
|
|
2aa36ee2a7 | ||
|
|
43affc22ab | ||
|
|
60575377d7 | ||
|
|
5ec8c7ed96 | ||
|
|
ef55a018f8 | ||
|
|
6bf9327f87 | ||
|
|
f761f93550 | ||
|
|
c996289563 | ||
|
|
89bbed42e6 | ||
|
|
8e22c0f3a4 | ||
|
|
3483c522da |
+8
-9
@@ -1,5 +1,4 @@
|
|||||||
language: python
|
language: python
|
||||||
dist: xenial
|
|
||||||
sudo: false
|
sudo: false
|
||||||
install:
|
install:
|
||||||
- pip install -U pip wheel setuptools
|
- pip install -U pip wheel setuptools
|
||||||
@@ -13,23 +12,23 @@ services:
|
|||||||
- postgresql
|
- postgresql
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_sqlite.cfg
|
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_sqlite.cfg
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=tests-cov PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
env: JOB=tests-cov PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=style
|
env: JOB=style
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_mysql.cfg
|
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_mysql.cfg
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||||
- python: 3.5
|
- python: 3.5
|
||||||
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
env: JOB=tests PRETIX_CONFIG_FILE=tests/travis_postgres.cfg
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=plugins
|
env: JOB=plugins
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=doc-spelling
|
env: JOB=doc-spelling
|
||||||
- python: 3.7
|
- python: 3.6
|
||||||
env: JOB=translation-spelling
|
env: JOB=translation-spelling
|
||||||
addons:
|
addons:
|
||||||
postgresql: "9.4"
|
postgresql: "9.4"
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ To build and run pretix, you will need the following debian packages::
|
|||||||
python3-dev libxml2-dev libxslt1-dev libffi-dev zlib1g-dev libssl-dev \
|
python3-dev libxml2-dev libxslt1-dev libffi-dev zlib1g-dev libssl-dev \
|
||||||
gettext libpq-dev libmariadbclient-dev libjpeg-dev libopenjp2-7-dev
|
gettext libpq-dev libmariadbclient-dev libjpeg-dev libopenjp2-7-dev
|
||||||
|
|
||||||
|
.. note:: Python 3.7 is not yet supported, so if you run a very recent OS, make sure to get
|
||||||
|
Python 3.6 from somewhere. You can check the current state of things in our
|
||||||
|
`Python 3.7 issue`_.
|
||||||
|
|
||||||
Config file
|
Config file
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@@ -310,3 +314,4 @@ example::
|
|||||||
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
.. _redis: https://blog.programster.org/debian-8-install-redis-server/
|
||||||
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
.. _ufw: https://en.wikipedia.org/wiki/Uncomplicated_Firewall
|
||||||
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
.. _strong encryption settings: https://mozilla.github.io/server-side-tls/ssl-config-generator/
|
||||||
|
.. _Python 3.7 issue: https://github.com/pretix/pretix/issues/1025
|
||||||
|
|||||||
@@ -181,37 +181,4 @@ as the string values ``true`` and ``false``.
|
|||||||
If the ``ordering`` parameter is documented for a resource, you can use it to sort the result set by one of the allowed
|
If the ``ordering`` parameter is documented for a resource, you can use it to sort the result set by one of the allowed
|
||||||
fields. Prepend a ``-`` to the field name to reverse the sort order.
|
fields. Prepend a ``-`` to the field name to reverse the sort order.
|
||||||
|
|
||||||
|
|
||||||
Idempotency
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Our API supports an idempotency mechanism to make sure you can safely retry operations without accidentally performing
|
|
||||||
them twice. This is useful if an API call experiences interruptions in transit, e.g. due to a network failure, and you
|
|
||||||
do not know if it completed successfully.
|
|
||||||
|
|
||||||
To perform an idempotent request, add a ``X-Idempotency-Key`` header with a random string value (we recommend a version
|
|
||||||
4 UUID) to your request. If we see a second request with the same ``X-Idempotency-Key`` and the same ``Authorization``
|
|
||||||
and ``Cookie`` headers, we will not perform the action for a second time but return the exact same response instead.
|
|
||||||
|
|
||||||
Please note that this also goes for most error responses. For example, if we returned you a ``403 Permission Denied``
|
|
||||||
error and you retry with the same ``X-Idempotency-Key``, you will get the same error again, even if you were granted
|
|
||||||
permission in the meantime! This includes internal server errors on our side that might have been fixed in the meantime.
|
|
||||||
|
|
||||||
There are only three exceptions to the rule:
|
|
||||||
|
|
||||||
* Responses with status code ``409 Conflict`` are not cached. If you send the request again, it will be executed as a
|
|
||||||
new request, since these responses are intended to be retried.
|
|
||||||
|
|
||||||
* Rate-limited responses with status code ``429 Too Many Requests`` are not cached and you can safely retry them.
|
|
||||||
|
|
||||||
* Responses with status code ``503 Service Unavailable`` are not cached and you can safely retry them.
|
|
||||||
|
|
||||||
If you send a request with an ``X-Idempotency-Key`` header that we have seen before but that has not yet received a
|
|
||||||
response, you will receive a response with status code ``409 Conflict`` and are asked to retry after five seconds.
|
|
||||||
|
|
||||||
We store idempotency keys for 24 hours, so you should never retry a request after a longer time period.
|
|
||||||
|
|
||||||
All ``POST``, ``PUT``, ``PATCH``, or ``DELETE`` api calls support idempotency keys. Adding an idempotency key to a
|
|
||||||
``GET``, ``HEAD``, or ``OPTIONS`` request has no effect.
|
|
||||||
|
|
||||||
.. _CSRF policies: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
|
.. _CSRF policies: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
|
||||||
|
|||||||
@@ -373,8 +373,8 @@ List of all orders
|
|||||||
}
|
}
|
||||||
|
|
||||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``datetime``, ``code``,
|
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``datetime``, ``code`` and
|
||||||
``last_modified``, and ``status``. Default: ``datetime``
|
``status``. Default: ``datetime``
|
||||||
:query string code: Only return orders that match the given order code
|
:query string code: Only return orders that match the given order code
|
||||||
:query string status: Only return orders in the given order status (see above)
|
:query string status: Only return orders in the given order status (see above)
|
||||||
:query boolean testmode: Only return orders with ``testmode`` set to ``true`` or ``false``
|
:query boolean testmode: Only return orders with ``testmode`` set to ``true`` or ``false``
|
||||||
@@ -385,7 +385,6 @@ List of all orders
|
|||||||
:query datetime modified_since: Only return orders that have changed since the given date. Be careful: We only
|
: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
|
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.
|
you will not notice it using this method.
|
||||||
:query datetime created_since: Only return orders that have been created since the given date.
|
|
||||||
:param organizer: The ``slug`` field of the organizer to fetch
|
:param organizer: The ``slug`` field of the organizer to fetch
|
||||||
:param event: The ``slug`` field of the event to fetch
|
:param event: The ``slug`` field of the event to fetch
|
||||||
:resheader X-Page-Generated: The server time at the beginning of the operation. If you're using this API to fetch
|
:resheader X-Page-Generated: The server time at the beginning of the operation. If you're using this API to fetch
|
||||||
@@ -750,7 +749,6 @@ Creating orders
|
|||||||
should only use this if you know the specific payment provider in detail. Please keep in mind that the payment
|
should only use this if you know the specific payment provider in detail. Please keep in mind that the payment
|
||||||
provider will not be called to do anything about this (i.e. if you pass a bank account to a debit provider, *no*
|
provider will not be called to do anything about this (i.e. if you pass a bank account to a debit provider, *no*
|
||||||
charge will be created), this is just informative in case you *handled the payment already*.
|
charge will be created), this is just informative in case you *handled the payment already*.
|
||||||
* ``payment_date`` (optional) – Date and time of the completion of the payment.
|
|
||||||
* ``comment`` (optional)
|
* ``comment`` (optional)
|
||||||
* ``checkin_attention`` (optional)
|
* ``checkin_attention`` (optional)
|
||||||
* ``invoice_address`` (optional)
|
* ``invoice_address`` (optional)
|
||||||
@@ -790,8 +788,6 @@ Creating orders
|
|||||||
* ``internal_type``
|
* ``internal_type``
|
||||||
* ``tax_rule``
|
* ``tax_rule``
|
||||||
|
|
||||||
* ``force`` (optional). If set to ``true``, quotas will be ignored.
|
|
||||||
|
|
||||||
If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually
|
If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually
|
||||||
to incrementing integers starting with ``1``. Then, you can reference one of these
|
to incrementing integers starting with ``1``. Then, you can reference one of these
|
||||||
IDs in the ``addon_to`` field of another position. Note that all add_ons for a specific position need to come
|
IDs in the ``addon_to`` field of another position. Note that all add_ons for a specific position need to come
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Order events
|
|||||||
There are multiple signals that will be sent out in the ordering cycle:
|
There are multiple signals that will be sent out in the ordering cycle:
|
||||||
|
|
||||||
.. automodule:: pretix.base.signals
|
.. automodule:: pretix.base.signals
|
||||||
:members: validate_cart, order_fee_calculation, order_paid, order_placed, order_canceled, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download
|
:members: validate_cart, order_fee_calculation, order_paid, order_placed, order_fee_type_name, allow_ticket_download
|
||||||
|
|
||||||
Frontend
|
Frontend
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "2.6.0"
|
__version__ = "2.6.0.dev0"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class DeviceTokenAuthentication(TokenAuthentication):
|
|||||||
if not device.initialized:
|
if not device.initialized:
|
||||||
raise exceptions.AuthenticationFailed('Device has not been initialized.')
|
raise exceptions.AuthenticationFailed('Device has not been initialized.')
|
||||||
|
|
||||||
if device.revoked:
|
if not device.api_token:
|
||||||
raise exceptions.AuthenticationFailed('Device access has been revoked.')
|
raise exceptions.AuthenticationFailed('Device access has been revoked.')
|
||||||
|
|
||||||
return AnonymousUser(), device
|
return AnonymousUser(), device
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
import json
|
|
||||||
from hashlib import sha1
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import transaction
|
|
||||||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
|
||||||
from django.utils.timezone import now
|
|
||||||
from rest_framework import status
|
|
||||||
|
|
||||||
from pretix.api.models import ApiCall
|
|
||||||
|
|
||||||
|
|
||||||
class IdempotencyMiddleware:
|
|
||||||
def __init__(self, get_response):
|
|
||||||
self.get_response = get_response
|
|
||||||
|
|
||||||
def __call__(self, request: HttpRequest):
|
|
||||||
if request.method in ('GET', 'HEAD', 'OPTIONS'):
|
|
||||||
return self.get_response(request)
|
|
||||||
|
|
||||||
if not request.path.startswith('/api/'):
|
|
||||||
return self.get_response(request)
|
|
||||||
|
|
||||||
if not request.headers.get('X-Idempotency-Key'):
|
|
||||||
return self.get_response(request)
|
|
||||||
|
|
||||||
auth_hash_parts = '{}:{}'.format(
|
|
||||||
request.headers.get('Authorization', ''),
|
|
||||||
request.COOKIES.get(settings.SESSION_COOKIE_NAME, '')
|
|
||||||
)
|
|
||||||
auth_hash = sha1(auth_hash_parts.encode()).hexdigest()
|
|
||||||
idempotency_key = request.headers.get('X-Idempotency-Key', '')
|
|
||||||
|
|
||||||
with transaction.atomic():
|
|
||||||
call, created = ApiCall.objects.select_for_update().get_or_create(
|
|
||||||
auth_hash=auth_hash,
|
|
||||||
idempotency_key=idempotency_key,
|
|
||||||
defaults={
|
|
||||||
'locked': now(),
|
|
||||||
'request_method': request.method,
|
|
||||||
'request_path': request.path,
|
|
||||||
'response_code': 0,
|
|
||||||
'response_headers': '{}',
|
|
||||||
'response_body': b''
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if created:
|
|
||||||
resp = self.get_response(request)
|
|
||||||
with transaction.atomic():
|
|
||||||
if resp.status_code in (409, 429, 503):
|
|
||||||
# This is the exception: These calls are *meant* to be retried!
|
|
||||||
call.delete()
|
|
||||||
else:
|
|
||||||
call.response_code = resp.status_code
|
|
||||||
if isinstance(resp.content, str):
|
|
||||||
call.response_body = resp.content.encode()
|
|
||||||
elif isinstance(resp.content, memoryview):
|
|
||||||
call.response_body = resp.content.tobytes()
|
|
||||||
elif isinstance(resp.content, bytes):
|
|
||||||
call.response_body = resp.content
|
|
||||||
elif hasattr(resp.content, 'read'):
|
|
||||||
call.response_body = resp.read()
|
|
||||||
elif hasattr(resp, 'data'):
|
|
||||||
call.response_body = json.dumps(resp.data)
|
|
||||||
else:
|
|
||||||
call.response_body = repr(resp).encode()
|
|
||||||
call.response_headers = json.dumps(resp._headers)
|
|
||||||
call.locked = None
|
|
||||||
call.save(update_fields=['locked', 'response_code', 'response_headers',
|
|
||||||
'response_body'])
|
|
||||||
return resp
|
|
||||||
else:
|
|
||||||
if call.locked:
|
|
||||||
r = JsonResponse(
|
|
||||||
{'detail': 'Concurrent request with idempotency key.'},
|
|
||||||
status=status.HTTP_409_CONFLICT,
|
|
||||||
)
|
|
||||||
r['Retry-After'] = 5
|
|
||||||
return r
|
|
||||||
|
|
||||||
content = call.response_body
|
|
||||||
if isinstance(content, memoryview):
|
|
||||||
content = content.tobytes()
|
|
||||||
r = HttpResponse(
|
|
||||||
content=content,
|
|
||||||
status=call.response_code,
|
|
||||||
)
|
|
||||||
for k, v in json.loads(call.response_headers).values():
|
|
||||||
r[k] = v
|
|
||||||
return r
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# Generated by Django 2.1.5 on 2019-04-05 10:48
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
('pretixbase', '0116_auto_20190402_0722'),
|
|
||||||
('pretixapi', '0003_webhook_webhookcall_webhookeventlistener'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='ApiCall',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('idempotency_key', models.CharField(db_index=True, max_length=190)),
|
|
||||||
('auth_hash', models.CharField(db_index=True, max_length=190)),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('locked', models.DateTimeField(null=True)),
|
|
||||||
('request_method', models.CharField(max_length=20)),
|
|
||||||
('request_path', models.CharField(max_length=255)),
|
|
||||||
('response_code', models.PositiveIntegerField()),
|
|
||||||
('response_headers', models.TextField()),
|
|
||||||
('response_body', models.BinaryField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='webhookcall',
|
|
||||||
options={'ordering': ('-datetime',)},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='webhookeventlistener',
|
|
||||||
options={'ordering': ('action_type',)},
|
|
||||||
),
|
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name='apicall',
|
|
||||||
unique_together={('idempotency_key', 'auth_hash')},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -77,9 +77,6 @@ class WebHook(models.Model):
|
|||||||
all_events = models.BooleanField(default=True, verbose_name=_("All events (including newly created ones)"))
|
all_events = models.BooleanField(default=True, verbose_name=_("All events (including newly created ones)"))
|
||||||
limit_events = models.ManyToManyField('pretixbase.Event', verbose_name=_("Limit to events"), blank=True)
|
limit_events = models.ManyToManyField('pretixbase.Event', verbose_name=_("Limit to events"), blank=True)
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ('id',)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def action_types(self):
|
def action_types(self):
|
||||||
return [
|
return [
|
||||||
@@ -109,20 +106,3 @@ class WebHookCall(models.Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ("-datetime",)
|
ordering = ("-datetime",)
|
||||||
|
|
||||||
|
|
||||||
class ApiCall(models.Model):
|
|
||||||
idempotency_key = models.CharField(max_length=190, db_index=True)
|
|
||||||
auth_hash = models.CharField(max_length=190, db_index=True)
|
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
|
||||||
locked = models.DateTimeField(null=True)
|
|
||||||
|
|
||||||
request_method = models.CharField(max_length=20)
|
|
||||||
request_path = models.CharField(max_length=255)
|
|
||||||
|
|
||||||
response_code = models.PositiveIntegerField()
|
|
||||||
response_headers = models.TextField()
|
|
||||||
response_body = models.BinaryField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
unique_together = (('idempotency_key', 'auth_hash'),)
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ class PluginsField(Field):
|
|||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
from pretix.base.plugins import get_all_plugins
|
from pretix.base.plugins import get_all_plugins
|
||||||
|
|
||||||
return sorted([
|
return {
|
||||||
p.module for p in get_all_plugins()
|
p.module for p in get_all_plugins()
|
||||||
if not p.name.startswith('.') and getattr(p, 'visible', True) and p.module in obj.get_plugins()
|
if not p.name.startswith('.') and getattr(p, 'visible', True) and p.module in obj.get_plugins()
|
||||||
])
|
}
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -457,13 +457,11 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
|||||||
payment_provider = serializers.CharField(required=True)
|
payment_provider = serializers.CharField(required=True)
|
||||||
payment_info = CompatibleJSONField(required=False)
|
payment_info = CompatibleJSONField(required=False)
|
||||||
consume_carts = serializers.ListField(child=serializers.CharField(), required=False)
|
consume_carts = serializers.ListField(child=serializers.CharField(), required=False)
|
||||||
force = serializers.BooleanField(default=False, required=False)
|
|
||||||
payment_date = serializers.DateTimeField(required=False, allow_null=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = ('code', 'status', 'testmode', 'email', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
|
fields = ('code', 'status', 'testmode', 'email', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
|
||||||
'invoice_address', 'positions', 'checkin_attention', 'payment_info', 'payment_date', 'consume_carts', 'force')
|
'invoice_address', 'positions', 'checkin_attention', 'payment_info', 'consume_carts')
|
||||||
|
|
||||||
def validate_payment_provider(self, pp):
|
def validate_payment_provider(self, pp):
|
||||||
if pp not in self.context['event'].get_payment_providers():
|
if pp not in self.context['event'].get_payment_providers():
|
||||||
@@ -534,8 +532,6 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
|||||||
positions_data = validated_data.pop('positions') if 'positions' in validated_data else []
|
positions_data = validated_data.pop('positions') if 'positions' in validated_data else []
|
||||||
payment_provider = validated_data.pop('payment_provider')
|
payment_provider = validated_data.pop('payment_provider')
|
||||||
payment_info = validated_data.pop('payment_info', '{}')
|
payment_info = validated_data.pop('payment_info', '{}')
|
||||||
payment_date = validated_data.pop('payment_date', now())
|
|
||||||
force = validated_data.pop('force', False)
|
|
||||||
|
|
||||||
if 'invoice_address' in validated_data:
|
if 'invoice_address' in validated_data:
|
||||||
iadata = validated_data.pop('invoice_address')
|
iadata = validated_data.pop('invoice_address')
|
||||||
@@ -569,30 +565,29 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
|||||||
|
|
||||||
errs = [{} for p in positions_data]
|
errs = [{} for p in positions_data]
|
||||||
|
|
||||||
if not force:
|
for i, pos_data in enumerate(positions_data):
|
||||||
for i, pos_data in enumerate(positions_data):
|
new_quotas = (pos_data.get('variation').quotas.filter(subevent=pos_data.get('subevent'))
|
||||||
new_quotas = (pos_data.get('variation').quotas.filter(subevent=pos_data.get('subevent'))
|
if pos_data.get('variation')
|
||||||
if pos_data.get('variation')
|
else pos_data.get('item').quotas.filter(subevent=pos_data.get('subevent')))
|
||||||
else pos_data.get('item').quotas.filter(subevent=pos_data.get('subevent')))
|
if len(new_quotas) == 0:
|
||||||
if len(new_quotas) == 0:
|
errs[i]['item'] = [ugettext_lazy('The product "{}" is not assigned to a quota.').format(
|
||||||
errs[i]['item'] = [ugettext_lazy('The product "{}" is not assigned to a quota.').format(
|
str(pos_data.get('item'))
|
||||||
str(pos_data.get('item'))
|
)]
|
||||||
)]
|
else:
|
||||||
else:
|
for quota in new_quotas:
|
||||||
for quota in new_quotas:
|
if quota not in quota_avail_cache:
|
||||||
if quota not in quota_avail_cache:
|
quota_avail_cache[quota] = list(quota.availability())
|
||||||
quota_avail_cache[quota] = list(quota.availability())
|
|
||||||
|
|
||||||
if quota_avail_cache[quota][1] is not None:
|
if quota_avail_cache[quota][1] is not None:
|
||||||
quota_avail_cache[quota][1] -= 1
|
quota_avail_cache[quota][1] -= 1
|
||||||
if quota_avail_cache[quota][1] < 0:
|
if quota_avail_cache[quota][1] < 0:
|
||||||
errs[i]['item'] = [
|
errs[i]['item'] = [
|
||||||
ugettext_lazy('There is not enough quota available on quota "{}" to perform the operation.').format(
|
ugettext_lazy('There is not enough quota available on quota "{}" to perform the operation.').format(
|
||||||
quota.name
|
quota.name
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
quotadiff.update(new_quotas)
|
quotadiff.update(new_quotas)
|
||||||
|
|
||||||
if any(errs):
|
if any(errs):
|
||||||
raise ValidationError({'positions': errs})
|
raise ValidationError({'positions': errs})
|
||||||
@@ -619,7 +614,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
|||||||
amount=order.total,
|
amount=order.total,
|
||||||
provider=payment_provider,
|
provider=payment_provider,
|
||||||
info=payment_info,
|
info=payment_info,
|
||||||
payment_date=payment_date,
|
payment_date=now(),
|
||||||
state=OrderPayment.PAYMENT_STATE_CONFIRMED
|
state=OrderPayment.PAYMENT_STATE_CONFIRMED
|
||||||
)
|
)
|
||||||
elif payment_provider:
|
elif payment_provider:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from datetime import timedelta
|
|||||||
from django.dispatch import Signal, receiver
|
from django.dispatch import Signal, receiver
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
from pretix.api.models import ApiCall, WebHookCall
|
from pretix.api.models import WebHookCall
|
||||||
from pretix.base.signals import periodic_task
|
from pretix.base.signals import periodic_task
|
||||||
|
|
||||||
register_webhook_events = Signal(
|
register_webhook_events = Signal(
|
||||||
@@ -19,8 +19,3 @@ instances.
|
|||||||
@receiver(periodic_task)
|
@receiver(periodic_task)
|
||||||
def cleanup_webhook_logs(sender, **kwargs):
|
def cleanup_webhook_logs(sender, **kwargs):
|
||||||
WebHookCall.objects.filter(datetime__lte=now() - timedelta(days=30)).delete()
|
WebHookCall.objects.filter(datetime__lte=now() - timedelta(days=30)).delete()
|
||||||
|
|
||||||
|
|
||||||
@receiver(periodic_task)
|
|
||||||
def cleanup_api_logs(sender, **kwargs):
|
|
||||||
ApiCall.objects.filter(created__lte=now() - timedelta(hours=24)).delete()
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ class RichOrderingFilter(OrderingFilter):
|
|||||||
class ConditionalListView:
|
class ConditionalListView:
|
||||||
|
|
||||||
def list(self, request, **kwargs):
|
def list(self, request, **kwargs):
|
||||||
if_modified_since = request.headers.get('If-Modified-Since')
|
if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE')
|
||||||
if if_modified_since:
|
if if_modified_since:
|
||||||
if_modified_since = parse_http_date_safe(if_modified_since)
|
if_modified_since = parse_http_date_safe(if_modified_since)
|
||||||
if_unmodified_since = request.headers.get('If-Unmodified-Since')
|
if_unmodified_since = request.META.get('HTTP_IF_UNMODIFIED_SINCE')
|
||||||
if if_unmodified_since:
|
if if_unmodified_since:
|
||||||
if_unmodified_since = parse_http_date_safe(if_unmodified_since)
|
if_unmodified_since = parse_http_date_safe(if_unmodified_since)
|
||||||
if not hasattr(request, 'event'):
|
if not hasattr(request, 'event'):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.utils.functional import cached_property
|
|||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import detail_route
|
||||||
from rest_framework.fields import DateTimeField
|
from rest_framework.fields import DateTimeField
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class CheckinListViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
super().perform_destroy(instance)
|
super().perform_destroy(instance)
|
||||||
|
|
||||||
@action(detail=True, methods=['GET'])
|
@detail_route(methods=['GET'])
|
||||||
def status(self, *args, **kwargs):
|
def status(self, *args, **kwargs):
|
||||||
clist = self.get_object()
|
clist = self.get_object()
|
||||||
cqs = Checkin.objects.filter(
|
cqs = Checkin.objects.filter(
|
||||||
@@ -242,7 +242,7 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
|
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def redeem(self, *args, **kwargs):
|
def redeem(self, *args, **kwargs):
|
||||||
force = bool(self.request.data.get('force', False))
|
force = bool(self.request.data.get('force', False))
|
||||||
ignore_unpaid = bool(self.request.data.get('ignore_unpaid', False))
|
ignore_unpaid = bool(self.request.data.get('ignore_unpaid', False))
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class RevokeKeyView(APIView):
|
|||||||
|
|
||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
device = request.auth
|
device = request.auth
|
||||||
device.revoked = True
|
device.api_token = None
|
||||||
device.save()
|
device.save()
|
||||||
device.log_action('pretix.device.revoked', auth=device)
|
device.log_action('pretix.device.revoked', auth=device)
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from pretix.api.serializers.event import (
|
|||||||
)
|
)
|
||||||
from pretix.api.views import ConditionalListView
|
from pretix.api.views import ConditionalListView
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CartPosition, Device, Event, ItemCategory, TaxRule, TeamAPIToken,
|
Device, Event, ItemCategory, TaxRule, TeamAPIToken,
|
||||||
)
|
)
|
||||||
from pretix.base.models.event import SubEvent
|
from pretix.base.models.event import SubEvent
|
||||||
from pretix.helpers.dicts import merge_dicts
|
from pretix.helpers.dicts import merge_dicts
|
||||||
@@ -272,8 +272,6 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
|||||||
auth=self.request.auth,
|
auth=self.request.auth,
|
||||||
data=self.request.data
|
data=self.request.data
|
||||||
)
|
)
|
||||||
CartPosition.objects.filter(addon_to__subevent=instance).delete()
|
|
||||||
instance.cartposition_set.all().delete()
|
|
||||||
super().perform_destroy(instance)
|
super().perform_destroy(instance)
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
raise PermissionDenied('The sub-event could not be deleted as some constraints (e.g. data created by '
|
raise PermissionDenied('The sub-event could not be deleted as some constraints (e.g. data created by '
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from django.shortcuts import get_object_or_404
|
|||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import detail_route
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.filters import OrderingFilter
|
from rest_framework.filters import OrderingFilter
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -16,8 +16,8 @@ from pretix.api.serializers.item import (
|
|||||||
)
|
)
|
||||||
from pretix.api.views import ConditionalListView
|
from pretix.api.views import ConditionalListView
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CartPosition, Item, ItemAddOn, ItemBundle, ItemCategory, ItemVariation,
|
Item, ItemAddOn, ItemBundle, ItemCategory, ItemVariation, Question,
|
||||||
Question, QuestionOption, Quota,
|
QuestionOption, Quota,
|
||||||
)
|
)
|
||||||
from pretix.helpers.dicts import merge_dicts
|
from pretix.helpers.dicts import merge_dicts
|
||||||
|
|
||||||
@@ -84,8 +84,7 @@ class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
|||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
auth=self.request.auth,
|
auth=self.request.auth,
|
||||||
)
|
)
|
||||||
CartPosition.objects.filter(addon_to__item=instance).delete()
|
self.get_object().cartposition_set.all().delete()
|
||||||
instance.cartposition_set.all().delete()
|
|
||||||
super().perform_destroy(instance)
|
super().perform_destroy(instance)
|
||||||
|
|
||||||
|
|
||||||
@@ -499,7 +498,7 @@ class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
super().perform_destroy(instance)
|
super().perform_destroy(instance)
|
||||||
|
|
||||||
@action(detail=True, methods=['get'])
|
@detail_route(methods=['get'])
|
||||||
def availability(self, request, *args, **kwargs):
|
def availability(self, request, *args, **kwargs):
|
||||||
quota = self.get_object()
|
quota = self.get_object()
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from django.utils.timezone import make_aware, now
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||||
from rest_framework import mixins, serializers, status, viewsets
|
from rest_framework import mixins, serializers, status, viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import detail_route
|
||||||
from rest_framework.exceptions import (
|
from rest_framework.exceptions import (
|
||||||
APIException, NotFound, PermissionDenied, ValidationError,
|
APIException, NotFound, PermissionDenied, ValidationError,
|
||||||
)
|
)
|
||||||
@@ -42,9 +42,7 @@ from pretix.base.services.orders import (
|
|||||||
extend_order, mark_order_expired, mark_order_refunded,
|
extend_order, mark_order_expired, mark_order_refunded,
|
||||||
)
|
)
|
||||||
from pretix.base.services.tickets import generate
|
from pretix.base.services.tickets import generate
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import order_placed, register_ticket_outputs
|
||||||
order_modified, order_placed, register_ticket_outputs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class OrderFilter(FilterSet):
|
class OrderFilter(FilterSet):
|
||||||
@@ -52,7 +50,6 @@ class OrderFilter(FilterSet):
|
|||||||
code = django_filters.CharFilter(field_name='code', lookup_expr='iexact')
|
code = django_filters.CharFilter(field_name='code', lookup_expr='iexact')
|
||||||
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
|
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
|
||||||
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
|
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
|
||||||
created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
@@ -127,7 +124,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
serializer = self.get_serializer(queryset, many=True)
|
serializer = self.get_serializer(queryset, many=True)
|
||||||
return Response(serializer.data, headers={'X-Page-Generated': date})
|
return Response(serializer.data, headers={'X-Page-Generated': date})
|
||||||
|
|
||||||
@action(detail=True, url_name='download', url_path='download/(?P<output>[^/]+)')
|
@detail_route(url_name='download', url_path='download/(?P<output>[^/]+)')
|
||||||
def download(self, request, output, **kwargs):
|
def download(self, request, output, **kwargs):
|
||||||
provider = self._get_output_provider(output)
|
provider = self._get_output_provider(output)
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
@@ -149,7 +146,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def mark_paid(self, request, **kwargs):
|
def mark_paid(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
|
|
||||||
@@ -190,7 +187,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
status=status.HTTP_400_BAD_REQUEST
|
status=status.HTTP_400_BAD_REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def mark_canceled(self, request, **kwargs):
|
def mark_canceled(self, request, **kwargs):
|
||||||
send_mail = request.data.get('send_email', True)
|
send_mail = request.data.get('send_email', True)
|
||||||
cancellation_fee = request.data.get('cancellation_fee', None)
|
cancellation_fee = request.data.get('cancellation_fee', None)
|
||||||
@@ -224,7 +221,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def approve(self, request, **kwargs):
|
def approve(self, request, **kwargs):
|
||||||
send_mail = request.data.get('send_email', True)
|
send_mail = request.data.get('send_email', True)
|
||||||
|
|
||||||
@@ -242,7 +239,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def deny(self, request, **kwargs):
|
def deny(self, request, **kwargs):
|
||||||
send_mail = request.data.get('send_email', True)
|
send_mail = request.data.get('send_email', True)
|
||||||
comment = request.data.get('comment', '')
|
comment = request.data.get('comment', '')
|
||||||
@@ -260,7 +257,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def mark_pending(self, request, **kwargs):
|
def mark_pending(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
|
|
||||||
@@ -279,7 +276,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def mark_expired(self, request, **kwargs):
|
def mark_expired(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
|
|
||||||
@@ -296,7 +293,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def mark_refunded(self, request, **kwargs):
|
def mark_refunded(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
|
|
||||||
@@ -313,7 +310,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def create_invoice(self, request, **kwargs):
|
def create_invoice(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
has_inv = order.invoices.exists() and not (
|
has_inv = order.invoices.exists() and not (
|
||||||
@@ -345,7 +342,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
status=status.HTTP_201_CREATED
|
status=status.HTTP_201_CREATED
|
||||||
)
|
)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def resend_link(self, request, **kwargs):
|
def resend_link(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
if not order.email:
|
if not order.email:
|
||||||
@@ -359,7 +356,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
status=status.HTTP_204_NO_CONTENT
|
status=status.HTTP_204_NO_CONTENT
|
||||||
)
|
)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def regenerate_secrets(self, request, **kwargs):
|
def regenerate_secrets(self, request, **kwargs):
|
||||||
order = self.get_object()
|
order = self.get_object()
|
||||||
@@ -377,7 +374,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def extend(self, request, **kwargs):
|
def extend(self, request, **kwargs):
|
||||||
new_date = request.data.get('expires', None)
|
new_date = request.data.get('expires', None)
|
||||||
force = request.data.get('force', False)
|
force = request.data.get('force', False)
|
||||||
@@ -453,64 +450,61 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
return super().update(request, *args, **kwargs)
|
return super().update(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def perform_update(self, serializer):
|
def perform_update(self, serializer):
|
||||||
with transaction.atomic():
|
if 'comment' in self.request.data and serializer.instance.comment != self.request.data.get('comment'):
|
||||||
if 'comment' in self.request.data and serializer.instance.comment != self.request.data.get('comment'):
|
serializer.instance.log_action(
|
||||||
serializer.instance.log_action(
|
'pretix.event.order.comment',
|
||||||
'pretix.event.order.comment',
|
user=self.request.user,
|
||||||
user=self.request.user,
|
auth=self.request.auth,
|
||||||
auth=self.request.auth,
|
data={
|
||||||
data={
|
'new_comment': self.request.data.get('comment')
|
||||||
'new_comment': self.request.data.get('comment')
|
}
|
||||||
}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if 'checkin_attention' in self.request.data and serializer.instance.checkin_attention != self.request.data.get('checkin_attention'):
|
if 'checkin_attention' in self.request.data and serializer.instance.checkin_attention != self.request.data.get('checkin_attention'):
|
||||||
serializer.instance.log_action(
|
serializer.instance.log_action(
|
||||||
'pretix.event.order.checkin_attention',
|
'pretix.event.order.checkin_attention',
|
||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
auth=self.request.auth,
|
auth=self.request.auth,
|
||||||
data={
|
data={
|
||||||
'new_value': self.request.data.get('checkin_attention')
|
'new_value': self.request.data.get('checkin_attention')
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'email' in self.request.data and serializer.instance.email != self.request.data.get('email'):
|
if 'email' in self.request.data and serializer.instance.email != self.request.data.get('email'):
|
||||||
serializer.instance.log_action(
|
serializer.instance.log_action(
|
||||||
'pretix.event.order.contact.changed',
|
'pretix.event.order.contact.changed',
|
||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
auth=self.request.auth,
|
auth=self.request.auth,
|
||||||
data={
|
data={
|
||||||
'old_email': serializer.instance.email,
|
'old_email': serializer.instance.email,
|
||||||
'new_email': self.request.data.get('email'),
|
'new_email': self.request.data.get('email'),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'locale' in self.request.data and serializer.instance.locale != self.request.data.get('locale'):
|
if 'locale' in self.request.data and serializer.instance.locale != self.request.data.get('locale'):
|
||||||
serializer.instance.log_action(
|
serializer.instance.log_action(
|
||||||
'pretix.event.order.locale.changed',
|
'pretix.event.order.locale.changed',
|
||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
auth=self.request.auth,
|
auth=self.request.auth,
|
||||||
data={
|
data={
|
||||||
'old_locale': serializer.instance.locale,
|
'old_locale': serializer.instance.locale,
|
||||||
'new_locale': self.request.data.get('locale'),
|
'new_locale': self.request.data.get('locale'),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'invoice_address' in self.request.data:
|
|
||||||
serializer.instance.log_action(
|
|
||||||
'pretix.event.order.modified',
|
|
||||||
user=self.request.user,
|
|
||||||
auth=self.request.auth,
|
|
||||||
data={
|
|
||||||
'invoice_data': self.request.data.get('invoice_address'),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
serializer.save()
|
|
||||||
|
|
||||||
if 'invoice_address' in self.request.data:
|
if 'invoice_address' in self.request.data:
|
||||||
order_modified.send(sender=serializer.instance.event, order=serializer.instance)
|
serializer.instance.log_action(
|
||||||
|
'pretix.event.order.modified',
|
||||||
|
user=self.request.user,
|
||||||
|
auth=self.request.auth,
|
||||||
|
data={
|
||||||
|
'invoice_data': self.request.data.get('invoice_address'),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
serializer.save()
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
serializer.save()
|
serializer.save()
|
||||||
@@ -619,7 +613,7 @@ class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewS
|
|||||||
return prov
|
return prov
|
||||||
raise NotFound('Unknown output provider.')
|
raise NotFound('Unknown output provider.')
|
||||||
|
|
||||||
@action(detail=True, url_name='download', url_path='download/(?P<output>[^/]+)')
|
@detail_route(url_name='download', url_path='download/(?P<output>[^/]+)')
|
||||||
def download(self, request, output, **kwargs):
|
def download(self, request, output, **kwargs):
|
||||||
provider = self._get_output_provider(output)
|
provider = self._get_output_provider(output)
|
||||||
pos = self.get_object()
|
pos = self.get_object()
|
||||||
@@ -670,7 +664,7 @@ class PaymentViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
order = get_object_or_404(Order, code=self.kwargs['order'], event=self.request.event)
|
order = get_object_or_404(Order, code=self.kwargs['order'], event=self.request.event)
|
||||||
return order.payments.all()
|
return order.payments.all()
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def confirm(self, request, **kwargs):
|
def confirm(self, request, **kwargs):
|
||||||
payment = self.get_object()
|
payment = self.get_object()
|
||||||
force = request.data.get('force', False)
|
force = request.data.get('force', False)
|
||||||
@@ -691,7 +685,7 @@ class PaymentViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
pass
|
pass
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def refund(self, request, **kwargs):
|
def refund(self, request, **kwargs):
|
||||||
payment = self.get_object()
|
payment = self.get_object()
|
||||||
amount = serializers.DecimalField(max_digits=10, decimal_places=2).to_internal_value(
|
amount = serializers.DecimalField(max_digits=10, decimal_places=2).to_internal_value(
|
||||||
@@ -756,7 +750,7 @@ class PaymentViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
payment.order.save(update_fields=['status', 'expires'])
|
payment.order.save(update_fields=['status', 'expires'])
|
||||||
return Response(OrderRefundSerializer(r).data, status=status.HTTP_200_OK)
|
return Response(OrderRefundSerializer(r).data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def cancel(self, request, **kwargs):
|
def cancel(self, request, **kwargs):
|
||||||
payment = self.get_object()
|
payment = self.get_object()
|
||||||
|
|
||||||
@@ -784,7 +778,7 @@ class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
|||||||
order = get_object_or_404(Order, code=self.kwargs['order'], event=self.request.event)
|
order = get_object_or_404(Order, code=self.kwargs['order'], event=self.request.event)
|
||||||
return order.refunds.all()
|
return order.refunds.all()
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def cancel(self, request, **kwargs):
|
def cancel(self, request, **kwargs):
|
||||||
refund = self.get_object()
|
refund = self.get_object()
|
||||||
|
|
||||||
@@ -801,7 +795,7 @@ class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
|||||||
}, user=self.request.user if self.request.user.is_authenticated else None, auth=self.request.auth)
|
}, user=self.request.user if self.request.user.is_authenticated else None, auth=self.request.auth)
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def process(self, request, **kwargs):
|
def process(self, request, **kwargs):
|
||||||
refund = self.get_object()
|
refund = self.get_object()
|
||||||
|
|
||||||
@@ -826,7 +820,7 @@ class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
|||||||
refund.order.save(update_fields=['status', 'expires'])
|
refund.order.save(update_fields=['status', 'expires'])
|
||||||
return self.retrieve(request, [], **kwargs)
|
return self.retrieve(request, [], **kwargs)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def done(self, request, **kwargs):
|
def done(self, request, **kwargs):
|
||||||
refund = self.get_object()
|
refund = self.get_object()
|
||||||
|
|
||||||
@@ -916,7 +910,7 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
nr=Concat('prefix', 'invoice_no')
|
nr=Concat('prefix', 'invoice_no')
|
||||||
)
|
)
|
||||||
|
|
||||||
@action(detail=True, )
|
@detail_route()
|
||||||
def download(self, request, **kwargs):
|
def download(self, request, **kwargs):
|
||||||
invoice = self.get_object()
|
invoice = self.get_object()
|
||||||
|
|
||||||
@@ -934,7 +928,7 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(invoice.number)
|
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(invoice.number)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def regenerate(self, request, **kwarts):
|
def regenerate(self, request, **kwarts):
|
||||||
inv = self.get_object()
|
inv = self.get_object()
|
||||||
if inv.canceled:
|
if inv.canceled:
|
||||||
@@ -953,7 +947,7 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
)
|
)
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def reissue(self, request, **kwarts):
|
def reissue(self, request, **kwarts):
|
||||||
inv = self.get_object()
|
inv = self.get_object()
|
||||||
if inv.canceled:
|
if inv.canceled:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django_filters.rest_framework import (
|
|||||||
BooleanFilter, DjangoFilterBackend, FilterSet,
|
BooleanFilter, DjangoFilterBackend, FilterSet,
|
||||||
)
|
)
|
||||||
from rest_framework import status, viewsets
|
from rest_framework import status, viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import list_route
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.filters import OrderingFilter
|
from rest_framework.filters import OrderingFilter
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -111,12 +111,9 @@ class VoucherViewSet(viewsets.ModelViewSet):
|
|||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
auth=self.request.auth,
|
auth=self.request.auth,
|
||||||
)
|
)
|
||||||
with transaction.atomic():
|
super().perform_destroy(instance)
|
||||||
instance.cartposition_set.filter(addon_to__isnull=False).delete()
|
|
||||||
instance.cartposition_set.all().delete()
|
|
||||||
super().perform_destroy(instance)
|
|
||||||
|
|
||||||
@action(detail=False, methods=['POST'])
|
@list_route(methods=['POST'])
|
||||||
def batch_create(self, request, *args, **kwargs):
|
def batch_create(self, request, *args, **kwargs):
|
||||||
if any(self._predict_quota_check(d, None) for d in request.data):
|
if any(self._predict_quota_check(d, None) for d in request.data):
|
||||||
lockfn = request.event.lock
|
lockfn = request.event.lock
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import django_filters
|
import django_filters
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import detail_route
|
||||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||||
from rest_framework.filters import OrderingFilter
|
from rest_framework.filters import OrderingFilter
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -69,7 +69,7 @@ class WaitingListViewSet(viewsets.ModelViewSet):
|
|||||||
)
|
)
|
||||||
super().perform_destroy(instance)
|
super().perform_destroy(instance)
|
||||||
|
|
||||||
@action(detail=True, methods=['POST'])
|
@detail_route(methods=['POST'])
|
||||||
def send_voucher(self, *args, **kwargs):
|
def send_voucher(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
self.get_object().send_voucher(
|
self.get_object().send_voucher(
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ class BaseQuestionsForm(forms.Form):
|
|||||||
initial = None
|
initial = None
|
||||||
tz = pytz.timezone(event.settings.timezone)
|
tz = pytz.timezone(event.settings.timezone)
|
||||||
help_text = rich_text(q.help_text)
|
help_text = rich_text(q.help_text)
|
||||||
|
default = q.default_value
|
||||||
label = escape(q.question) # django-bootstrap3 calls mark_safe
|
label = escape(q.question) # django-bootstrap3 calls mark_safe
|
||||||
required = q.required and not self.all_optional
|
required = q.required and not self.all_optional
|
||||||
if q.type == Question.TYPE_BOOLEAN:
|
if q.type == Question.TYPE_BOOLEAN:
|
||||||
@@ -185,6 +186,8 @@ class BaseQuestionsForm(forms.Form):
|
|||||||
|
|
||||||
if initial:
|
if initial:
|
||||||
initialbool = (initial.answer == "True")
|
initialbool = (initial.answer == "True")
|
||||||
|
elif default:
|
||||||
|
initialbool = (default == "True")
|
||||||
else:
|
else:
|
||||||
initialbool = False
|
initialbool = False
|
||||||
|
|
||||||
@@ -197,21 +200,21 @@ class BaseQuestionsForm(forms.Form):
|
|||||||
field = forms.DecimalField(
|
field = forms.DecimalField(
|
||||||
label=label, required=required,
|
label=label, required=required,
|
||||||
help_text=q.help_text,
|
help_text=q.help_text,
|
||||||
initial=initial.answer if initial else None,
|
initial=initial.answer if initial else (default if default else None),
|
||||||
min_value=Decimal('0.00'),
|
min_value=Decimal('0.00'),
|
||||||
)
|
)
|
||||||
elif q.type == Question.TYPE_STRING:
|
elif q.type == Question.TYPE_STRING:
|
||||||
field = forms.CharField(
|
field = forms.CharField(
|
||||||
label=label, required=required,
|
label=label, required=required,
|
||||||
help_text=help_text,
|
help_text=help_text,
|
||||||
initial=initial.answer if initial else None,
|
initial=initial.answer if initial else (default if default else None),
|
||||||
)
|
)
|
||||||
elif q.type == Question.TYPE_TEXT:
|
elif q.type == Question.TYPE_TEXT:
|
||||||
field = forms.CharField(
|
field = forms.CharField(
|
||||||
label=label, required=required,
|
label=label, required=required,
|
||||||
help_text=help_text,
|
help_text=help_text,
|
||||||
widget=forms.Textarea,
|
widget=forms.Textarea,
|
||||||
initial=initial.answer if initial else None,
|
initial=initial.answer if initial else (default if default else None),
|
||||||
)
|
)
|
||||||
elif q.type == Question.TYPE_CHOICE:
|
elif q.type == Question.TYPE_CHOICE:
|
||||||
field = forms.ModelChoiceField(
|
field = forms.ModelChoiceField(
|
||||||
@@ -243,21 +246,24 @@ class BaseQuestionsForm(forms.Form):
|
|||||||
field = forms.DateField(
|
field = forms.DateField(
|
||||||
label=label, required=required,
|
label=label, required=required,
|
||||||
help_text=help_text,
|
help_text=help_text,
|
||||||
initial=dateutil.parser.parse(initial.answer).date() if initial and initial.answer else None,
|
initial=dateutil.parser.parse(initial.answer).date() if initial and initial.answer else (
|
||||||
|
dateutil.parser.parse(default).date() if default else None),
|
||||||
widget=DatePickerWidget(),
|
widget=DatePickerWidget(),
|
||||||
)
|
)
|
||||||
elif q.type == Question.TYPE_TIME:
|
elif q.type == Question.TYPE_TIME:
|
||||||
field = forms.TimeField(
|
field = forms.TimeField(
|
||||||
label=label, required=required,
|
label=label, required=required,
|
||||||
help_text=help_text,
|
help_text=help_text,
|
||||||
initial=dateutil.parser.parse(initial.answer).time() if initial and initial.answer else None,
|
initial=dateutil.parser.parse(initial.answer).time() if initial and initial.answer else (
|
||||||
|
dateutil.parser.parse(default).time() if default else None),
|
||||||
widget=TimePickerWidget(time_format=get_format_without_seconds('TIME_INPUT_FORMATS')),
|
widget=TimePickerWidget(time_format=get_format_without_seconds('TIME_INPUT_FORMATS')),
|
||||||
)
|
)
|
||||||
elif q.type == Question.TYPE_DATETIME:
|
elif q.type == Question.TYPE_DATETIME:
|
||||||
field = SplitDateTimeField(
|
field = SplitDateTimeField(
|
||||||
label=label, required=required,
|
label=label, required=required,
|
||||||
help_text=help_text,
|
help_text=help_text,
|
||||||
initial=dateutil.parser.parse(initial.answer).astimezone(tz) if initial and initial.answer else None,
|
initial=dateutil.parser.parse(initial.answer).astimezone(tz) if initial and initial.answer else (
|
||||||
|
dateutil.parser.parse(default).astimezone(tz) if default else None),
|
||||||
widget=SplitDateTimePickerWidget(time_format=get_format_without_seconds('TIME_INPUT_FORMATS')),
|
widget=SplitDateTimePickerWidget(time_format=get_format_without_seconds('TIME_INPUT_FORMATS')),
|
||||||
)
|
)
|
||||||
field.question = q
|
field.question = q
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ def get_language_from_event(request: HttpRequest) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def get_language_from_browser(request: HttpRequest) -> str:
|
def get_language_from_browser(request: HttpRequest) -> str:
|
||||||
accept = request.headers.get('Accept-Language', '')
|
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
|
||||||
for accept_lang, unused in parse_accept_lang_header(accept):
|
for accept_lang, unused in parse_accept_lang_header(accept):
|
||||||
if accept_lang == '*':
|
if accept_lang == '*':
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.13 on 2018-05-31 15:39
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pretixbase', '0115_auto_20190323_2238'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='question',
|
||||||
|
name='default_value',
|
||||||
|
field=models.TextField(blank=True, help_text='The question will be filled with this response by default', null=True, verbose_name='Default answer'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 2.1.5 on 2019-04-02 07:22
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
import jsonfallback.fields
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
import pretix.base.models.fields
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('pretixbase', '0115_auto_20190323_2238'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='device',
|
|
||||||
name='revoked',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -111,7 +111,6 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("User")
|
verbose_name = _("User")
|
||||||
verbose_name_plural = _("Users")
|
verbose_name_plural = _("Users")
|
||||||
ordering = ('email',)
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.email = self.email.lower()
|
self.email = self.email.lower()
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ class Device(LoggedModel):
|
|||||||
api_token = models.CharField(max_length=190, unique=True, null=True)
|
api_token = models.CharField(max_length=190, unique=True, null=True)
|
||||||
all_events = models.BooleanField(default=False, verbose_name=_("All events (including newly created ones)"))
|
all_events = models.BooleanField(default=False, verbose_name=_("All events (including newly created ones)"))
|
||||||
limit_events = models.ManyToManyField('Event', verbose_name=_("Limit to events"), blank=True)
|
limit_events = models.ManyToManyField('Event', verbose_name=_("Limit to events"), blank=True)
|
||||||
revoked = models.BooleanField(default=False)
|
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=190,
|
max_length=190,
|
||||||
verbose_name=_('Name')
|
verbose_name=_('Name')
|
||||||
|
|||||||
@@ -759,7 +759,6 @@ class Event(EventMixin, LoggedModel):
|
|||||||
return not self.orders.exists() and not self.invoices.exists()
|
return not self.orders.exists() and not self.invoices.exists()
|
||||||
|
|
||||||
def delete_sub_objects(self):
|
def delete_sub_objects(self):
|
||||||
self.cartposition_set.filter(addon_to__isnull=False).delete()
|
|
||||||
self.cartposition_set.all().delete()
|
self.cartposition_set.all().delete()
|
||||||
self.items.all().delete()
|
self.items.all().delete()
|
||||||
self.subevents.all().delete()
|
self.subevents.all().delete()
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class MultiStringField(TextField):
|
|||||||
def get_prep_lookup(self, lookup_type, value): # NOQA
|
def get_prep_lookup(self, lookup_type, value): # NOQA
|
||||||
raise TypeError('Lookups on multi strings are currently not supported.')
|
raise TypeError('Lookups on multi strings are currently not supported.')
|
||||||
|
|
||||||
def from_db_value(self, value, expression, connection):
|
def from_db_value(self, value, expression, connection, context):
|
||||||
if value:
|
if value:
|
||||||
return [v for v in value.split(DELIMITER) if v]
|
return [v for v in value.split(DELIMITER) if v]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -963,6 +963,11 @@ class Question(LoggedModel):
|
|||||||
'Question', null=True, blank=True, on_delete=models.SET_NULL, related_name='dependent_questions'
|
'Question', null=True, blank=True, on_delete=models.SET_NULL, related_name='dependent_questions'
|
||||||
)
|
)
|
||||||
dependency_value = models.TextField(null=True, blank=True)
|
dependency_value = models.TextField(null=True, blank=True)
|
||||||
|
default_value = models.TextField(
|
||||||
|
verbose_name=_('Default answer'),
|
||||||
|
help_text=_('The question will be filled with this response by default'),
|
||||||
|
null=True, blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Question")
|
verbose_name = _("Question")
|
||||||
@@ -980,6 +985,10 @@ class Question(LoggedModel):
|
|||||||
def clean_identifier(self, code):
|
def clean_identifier(self, code):
|
||||||
Question._clean_identifier(self.event, code, self)
|
Question._clean_identifier(self.event, code, self)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if self.default_value is not None:
|
||||||
|
self.clean_answer(self.default_value, check_required=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _clean_identifier(event, code, instance=None):
|
def _clean_identifier(event, code, instance=None):
|
||||||
qs = Question.objects.filter(event=event, identifier__iexact=code)
|
qs = Question.objects.filter(event=event, identifier__iexact=code)
|
||||||
@@ -1007,8 +1016,8 @@ class Question(LoggedModel):
|
|||||||
def __lt__(self, other) -> bool:
|
def __lt__(self, other) -> bool:
|
||||||
return self.sortkey < other.sortkey
|
return self.sortkey < other.sortkey
|
||||||
|
|
||||||
def clean_answer(self, answer):
|
def clean_answer(self, answer, check_required=True):
|
||||||
if self.required:
|
if self.required and check_required:
|
||||||
if not answer or (self.type == Question.TYPE_BOOLEAN and answer not in ("true", "True", True)):
|
if not answer or (self.type == Question.TYPE_BOOLEAN and answer not in ("true", "True", True)):
|
||||||
raise ValidationError(_('An answer to this question is required to proceed.'))
|
raise ValidationError(_('An answer to this question is required to proceed.'))
|
||||||
if not answer:
|
if not answer:
|
||||||
|
|||||||
@@ -1159,7 +1159,7 @@ class OrderPayment(models.Model):
|
|||||||
self.order.log_action('pretix.event.order.overpaid', {}, user=user, auth=auth)
|
self.order.log_action('pretix.event.order.overpaid', {}, user=user, auth=auth)
|
||||||
order_paid.send(self.order.event, order=self.order)
|
order_paid.send(self.order.event, order=self.order)
|
||||||
|
|
||||||
def confirm(self, count_waitinglist=True, send_mail=True, force=False, user=None, auth=None, mail_text='', lock=True):
|
def confirm(self, count_waitinglist=True, send_mail=True, force=False, user=None, auth=None, mail_text=''):
|
||||||
"""
|
"""
|
||||||
Marks the payment as complete. If possible, this also marks the order as paid if no further
|
Marks the payment as complete. If possible, this also marks the order as paid if no further
|
||||||
payment is required
|
payment is required
|
||||||
@@ -1218,7 +1218,7 @@ class OrderPayment(models.Model):
|
|||||||
if payment_sum - refund_sum < self.order.total:
|
if payment_sum - refund_sum < self.order.total:
|
||||||
return
|
return
|
||||||
|
|
||||||
if (self.order.status == Order.STATUS_PENDING and self.order.expires > now() + timedelta(hours=12)) or not lock:
|
if self.order.status == Order.STATUS_PENDING and self.order.expires > now() + timedelta(hours=12):
|
||||||
# Performance optimization. In this case, there's really no reason to lock everything and an atomic
|
# Performance optimization. In this case, there's really no reason to lock everything and an atomic
|
||||||
# database transaction is more than enough.
|
# database transaction is more than enough.
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
|||||||
@@ -118,9 +118,6 @@ class TaxRule(LoggedModel):
|
|||||||
)
|
)
|
||||||
custom_rules = models.TextField(blank=True, null=True)
|
custom_rules = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ('event', 'rate', 'id')
|
|
||||||
|
|
||||||
def allow_delete(self):
|
def allow_delete(self):
|
||||||
from pretix.base.models.orders import OrderFee, OrderPosition
|
from pretix.base.models.orders import OrderFee, OrderPosition
|
||||||
|
|
||||||
|
|||||||
@@ -721,10 +721,13 @@ class BoxOfficeProvider(BasePaymentProvider):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def payment_control_render(self, request, payment) -> str:
|
def payment_control_render(self, request, payment) -> str:
|
||||||
if not payment.info:
|
template = None
|
||||||
return
|
payment_info = None
|
||||||
payment_info = json.loads(payment.info)
|
|
||||||
template = get_template('pretixcontrol/boxoffice/payment.html')
|
if payment.info:
|
||||||
|
payment_info = json.loads(payment.info)
|
||||||
|
if payment_info['payment_type'] == "sumup":
|
||||||
|
template = get_template('pretixcontrol/boxoffice/payment_sumup.html')
|
||||||
|
|
||||||
ctx = {
|
ctx = {
|
||||||
'request': request,
|
'request': request,
|
||||||
@@ -734,7 +737,11 @@ class BoxOfficeProvider(BasePaymentProvider):
|
|||||||
'payment': payment,
|
'payment': payment,
|
||||||
'provider': self,
|
'provider': self,
|
||||||
}
|
}
|
||||||
return template.render(ctx)
|
|
||||||
|
if template:
|
||||||
|
return template.render(ctx)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class ManualPayment(BasePaymentProvider):
|
class ManualPayment(BasePaymentProvider):
|
||||||
|
|||||||
@@ -276,10 +276,6 @@ class CartManager:
|
|||||||
err = None
|
err = None
|
||||||
changed_prices = {}
|
changed_prices = {}
|
||||||
for cp in expired:
|
for cp in expired:
|
||||||
removed_positions = {op.position.pk for op in self._operations if isinstance(op, self.RemoveOperation)}
|
|
||||||
if cp.pk in removed_positions or (cp.addon_to_id and cp.addon_to_id in removed_positions):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if cp.is_bundled:
|
if cp.is_bundled:
|
||||||
try:
|
try:
|
||||||
bundle = cp.addon_to.item.bundles.get(bundled_item=cp.item, bundled_variation=cp.variation)
|
bundle = cp.addon_to.item.bundles.get(bundled_item=cp.item, bundled_variation=cp.variation)
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
|||||||
positions = list(
|
positions = list(
|
||||||
invoice.order.positions.select_related('addon_to', 'item', 'tax_rule', 'subevent', 'variation').annotate(
|
invoice.order.positions.select_related('addon_to', 'item', 'tax_rule', 'subevent', 'variation').annotate(
|
||||||
addon_c=Count('addons')
|
addon_c=Count('addons')
|
||||||
).order_by('positionid', 'id')
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
reverse_charge = False
|
reverse_charge = False
|
||||||
|
|||||||
@@ -212,30 +212,15 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
|
|||||||
order = None
|
order = None
|
||||||
else:
|
else:
|
||||||
if attach_tickets:
|
if attach_tickets:
|
||||||
args = []
|
|
||||||
attach_size = 0
|
|
||||||
for name, ct in get_tickets_for_order(order):
|
for name, ct in get_tickets_for_order(order):
|
||||||
content = ct.file.read()
|
try:
|
||||||
args.append((name, content, ct.type))
|
email.attach(
|
||||||
attach_size += len(content)
|
name,
|
||||||
|
ct.file.read(),
|
||||||
if attach_size < 4 * 1024 * 1024:
|
ct.type
|
||||||
# Do not attach more than 4MB, it will bounce way to often.
|
)
|
||||||
for a in args:
|
except:
|
||||||
try:
|
pass
|
||||||
email.attach(*a)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
order.log_action(
|
|
||||||
'pretix.event.order.email.error',
|
|
||||||
data={
|
|
||||||
'subject': 'Attachments skipped',
|
|
||||||
'message': 'Attachment have not been send because {} bytes are likely too large to arrive.'.format(attach_size),
|
|
||||||
'recipient': '',
|
|
||||||
'invoices': [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
email = email_filter.send_chained(event, 'message', message=email, order=order)
|
email = email_filter.send_chained(event, 'message', message=email, order=order)
|
||||||
|
|
||||||
|
|||||||
+123
-138
@@ -42,9 +42,7 @@ from pretix.base.services.mail import SendMailException
|
|||||||
from pretix.base.services.pricing import get_price
|
from pretix.base.services.pricing import get_price
|
||||||
from pretix.base.services.tasks import ProfiledTask
|
from pretix.base.services.tasks import ProfiledTask
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
allow_ticket_download, order_approved, order_canceled, order_changed,
|
allow_ticket_download, order_fee_calculation, order_placed, periodic_task,
|
||||||
order_denied, order_expired, order_fee_calculation, order_placed,
|
|
||||||
periodic_task,
|
|
||||||
)
|
)
|
||||||
from pretix.celery_app import app
|
from pretix.celery_app import app
|
||||||
from pretix.helpers.models import modelcopy
|
from pretix.helpers.models import modelcopy
|
||||||
@@ -136,58 +134,55 @@ def mark_order_refunded(order, user=None, auth=None, api_token=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def mark_order_expired(order, user=None, auth=None):
|
def mark_order_expired(order, user=None, auth=None):
|
||||||
"""
|
"""
|
||||||
Mark this order as expired. This sets the payment status and returns the order object.
|
Mark this order as expired. This sets the payment status and returns the order object.
|
||||||
:param order: The order to change
|
:param order: The order to change
|
||||||
:param user: The user that performed the change
|
:param user: The user that performed the change
|
||||||
"""
|
"""
|
||||||
with transaction.atomic():
|
if isinstance(order, int):
|
||||||
if isinstance(order, int):
|
order = Order.objects.get(pk=order)
|
||||||
order = Order.objects.get(pk=order)
|
if isinstance(user, int):
|
||||||
if isinstance(user, int):
|
user = User.objects.get(pk=user)
|
||||||
user = User.objects.get(pk=user)
|
with order.event.lock():
|
||||||
with order.event.lock():
|
order.status = Order.STATUS_EXPIRED
|
||||||
order.status = Order.STATUS_EXPIRED
|
order.save(update_fields=['status'])
|
||||||
order.save(update_fields=['status'])
|
|
||||||
|
|
||||||
order.log_action('pretix.event.order.expired', user=user, auth=auth)
|
order.log_action('pretix.event.order.expired', user=user, auth=auth)
|
||||||
i = order.invoices.filter(is_cancellation=False).last()
|
i = order.invoices.filter(is_cancellation=False).last()
|
||||||
if i:
|
if i:
|
||||||
generate_cancellation(i)
|
generate_cancellation(i)
|
||||||
|
|
||||||
order_expired.send(order.event, order=order)
|
|
||||||
return order
|
return order
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def approve_order(order, user=None, send_mail: bool=True, auth=None):
|
def approve_order(order, user=None, send_mail: bool=True, auth=None):
|
||||||
"""
|
"""
|
||||||
Mark this order as approved
|
Mark this order as approved
|
||||||
:param order: The order to change
|
:param order: The order to change
|
||||||
:param user: The user that performed the change
|
:param user: The user that performed the change
|
||||||
"""
|
"""
|
||||||
with transaction.atomic():
|
if not order.require_approval or not order.status == Order.STATUS_PENDING:
|
||||||
if not order.require_approval or not order.status == Order.STATUS_PENDING:
|
raise OrderError(_('This order is not pending approval.'))
|
||||||
raise OrderError(_('This order is not pending approval.'))
|
|
||||||
|
|
||||||
order.require_approval = False
|
order.require_approval = False
|
||||||
order.set_expires(now(), order.event.subevents.filter(id__in=[p.subevent_id for p in order.positions.all()]))
|
order.set_expires(now(), order.event.subevents.filter(id__in=[p.subevent_id for p in order.positions.all()]))
|
||||||
order.save(update_fields=['require_approval', 'expires'])
|
order.save(update_fields=['require_approval', 'expires'])
|
||||||
|
|
||||||
order.log_action('pretix.event.order.approved', user=user, auth=auth)
|
order.log_action('pretix.event.order.approved', user=user, auth=auth)
|
||||||
if order.total == Decimal('0.00'):
|
if order.total == Decimal('0.00'):
|
||||||
p = order.payments.create(
|
p = order.payments.create(
|
||||||
state=OrderPayment.PAYMENT_STATE_CREATED,
|
state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||||
provider='free',
|
provider='free',
|
||||||
amount=0,
|
amount=0,
|
||||||
fee=None
|
fee=None
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
p.confirm(send_mail=False, count_waitinglist=False, user=user, auth=auth)
|
p.confirm(send_mail=False, count_waitinglist=False, user=user, auth=auth)
|
||||||
except Quota.QuotaExceededException:
|
except Quota.QuotaExceededException:
|
||||||
raise OrderError(error_messages['unavailable'])
|
raise OrderError(error_messages['unavailable'])
|
||||||
|
|
||||||
order_approved.send(order.event, order=order)
|
|
||||||
|
|
||||||
invoice = order.invoices.last() # Might be generated by plugin already
|
invoice = order.invoices.last() # Might be generated by plugin already
|
||||||
if order.event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
|
if order.event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
|
||||||
@@ -239,32 +234,30 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None):
|
|||||||
return order.pk
|
return order.pk
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
|
def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
|
||||||
"""
|
"""
|
||||||
Mark this order as canceled
|
Mark this order as canceled
|
||||||
:param order: The order to change
|
:param order: The order to change
|
||||||
:param user: The user that performed the change
|
:param user: The user that performed the change
|
||||||
"""
|
"""
|
||||||
with transaction.atomic():
|
if not order.require_approval or not order.status == Order.STATUS_PENDING:
|
||||||
if not order.require_approval or not order.status == Order.STATUS_PENDING:
|
raise OrderError(_('This order is not pending approval.'))
|
||||||
raise OrderError(_('This order is not pending approval.'))
|
|
||||||
|
|
||||||
with order.event.lock():
|
with order.event.lock():
|
||||||
order.status = Order.STATUS_CANCELED
|
order.status = Order.STATUS_CANCELED
|
||||||
order.save(update_fields=['status'])
|
order.save(update_fields=['status'])
|
||||||
|
|
||||||
order.log_action('pretix.event.order.denied', user=user, auth=auth, data={
|
order.log_action('pretix.event.order.denied', user=user, auth=auth, data={
|
||||||
'comment': comment
|
'comment': comment
|
||||||
})
|
})
|
||||||
i = order.invoices.filter(is_cancellation=False).last()
|
i = order.invoices.filter(is_cancellation=False).last()
|
||||||
if i:
|
if i:
|
||||||
generate_cancellation(i)
|
generate_cancellation(i)
|
||||||
|
|
||||||
for position in order.positions.all():
|
for position in order.positions.all():
|
||||||
if position.voucher:
|
if position.voucher:
|
||||||
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
||||||
|
|
||||||
order_denied.send(order.event, order=order)
|
|
||||||
|
|
||||||
if send_mail:
|
if send_mail:
|
||||||
try:
|
try:
|
||||||
@@ -301,6 +294,7 @@ def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
|
|||||||
return order.pk
|
return order.pk
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device=None, oauth_application=None,
|
def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device=None, oauth_application=None,
|
||||||
cancellation_fee=None):
|
cancellation_fee=None):
|
||||||
"""
|
"""
|
||||||
@@ -308,87 +302,85 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
|
|||||||
:param order: The order to change
|
:param order: The order to change
|
||||||
:param user: The user that performed the change
|
:param user: The user that performed the change
|
||||||
"""
|
"""
|
||||||
with transaction.atomic():
|
if isinstance(order, int):
|
||||||
if isinstance(order, int):
|
order = Order.objects.get(pk=order)
|
||||||
order = Order.objects.get(pk=order)
|
if isinstance(user, int):
|
||||||
if isinstance(user, int):
|
user = User.objects.get(pk=user)
|
||||||
user = User.objects.get(pk=user)
|
if isinstance(api_token, int):
|
||||||
if isinstance(api_token, int):
|
api_token = TeamAPIToken.objects.get(pk=api_token)
|
||||||
api_token = TeamAPIToken.objects.get(pk=api_token)
|
if isinstance(device, int):
|
||||||
if isinstance(device, int):
|
device = Device.objects.get(pk=device)
|
||||||
device = Device.objects.get(pk=device)
|
if isinstance(oauth_application, int):
|
||||||
if isinstance(oauth_application, int):
|
oauth_application = OAuthApplication.objects.get(pk=oauth_application)
|
||||||
oauth_application = OAuthApplication.objects.get(pk=oauth_application)
|
if isinstance(cancellation_fee, str):
|
||||||
if isinstance(cancellation_fee, str):
|
cancellation_fee = Decimal(cancellation_fee)
|
||||||
cancellation_fee = Decimal(cancellation_fee)
|
|
||||||
|
|
||||||
if not order.cancel_allowed():
|
if not order.cancel_allowed():
|
||||||
raise OrderError(_('You cannot cancel this order.'))
|
raise OrderError(_('You cannot cancel this order.'))
|
||||||
i = order.invoices.filter(is_cancellation=False).last()
|
i = order.invoices.filter(is_cancellation=False).last()
|
||||||
if i:
|
if i:
|
||||||
generate_cancellation(i)
|
generate_cancellation(i)
|
||||||
|
|
||||||
if cancellation_fee:
|
|
||||||
with order.event.lock():
|
|
||||||
for position in order.positions.all():
|
|
||||||
if position.voucher:
|
|
||||||
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
|
||||||
position.canceled = True
|
|
||||||
position.save(update_fields=['canceled'])
|
|
||||||
for fee in order.fees.all():
|
|
||||||
fee.canceled = True
|
|
||||||
fee.save(update_fields=['canceled'])
|
|
||||||
|
|
||||||
f = OrderFee(
|
|
||||||
fee_type=OrderFee.FEE_TYPE_CANCELLATION,
|
|
||||||
value=cancellation_fee,
|
|
||||||
tax_rule=order.event.settings.tax_rate_default,
|
|
||||||
order=order,
|
|
||||||
)
|
|
||||||
f._calculate_tax()
|
|
||||||
f.save()
|
|
||||||
|
|
||||||
if order.payment_refund_sum < cancellation_fee:
|
|
||||||
raise OrderError(_('The cancellation fee cannot be higher than the payment credit of this order.'))
|
|
||||||
order.status = Order.STATUS_PAID
|
|
||||||
order.total = f.value
|
|
||||||
order.save(update_fields=['status', 'total'])
|
|
||||||
|
|
||||||
if i:
|
|
||||||
generate_invoice(order)
|
|
||||||
else:
|
|
||||||
with order.event.lock():
|
|
||||||
order.status = Order.STATUS_CANCELED
|
|
||||||
order.save(update_fields=['status'])
|
|
||||||
|
|
||||||
|
if cancellation_fee:
|
||||||
|
with order.event.lock():
|
||||||
for position in order.positions.all():
|
for position in order.positions.all():
|
||||||
if position.voucher:
|
if position.voucher:
|
||||||
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
||||||
|
position.canceled = True
|
||||||
|
position.save(update_fields=['canceled'])
|
||||||
|
for fee in order.fees.all():
|
||||||
|
fee.canceled = True
|
||||||
|
fee.save(update_fields=['canceled'])
|
||||||
|
|
||||||
order.log_action('pretix.event.order.canceled', user=user, auth=api_token or oauth_application or device,
|
f = OrderFee(
|
||||||
data={'cancellation_fee': cancellation_fee})
|
fee_type=OrderFee.FEE_TYPE_CANCELLATION,
|
||||||
|
value=cancellation_fee,
|
||||||
|
tax_rule=order.event.settings.tax_rate_default,
|
||||||
|
order=order,
|
||||||
|
)
|
||||||
|
f._calculate_tax()
|
||||||
|
f.save()
|
||||||
|
|
||||||
if send_mail:
|
if order.payment_refund_sum < cancellation_fee:
|
||||||
email_template = order.event.settings.mail_text_order_canceled
|
raise OrderError(_('The cancellation fee cannot be higher than the payment credit of this order.'))
|
||||||
email_context = {
|
order.status = Order.STATUS_PAID
|
||||||
'event': order.event.name,
|
order.total = f.value
|
||||||
'code': order.code,
|
order.save(update_fields=['status', 'total'])
|
||||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
|
||||||
'order': order.code,
|
if i:
|
||||||
'secret': order.secret
|
generate_invoice(order)
|
||||||
})
|
else:
|
||||||
}
|
with order.event.lock():
|
||||||
with language(order.locale):
|
order.status = Order.STATUS_CANCELED
|
||||||
email_subject = _('Order canceled: %(code)s') % {'code': order.code}
|
order.save(update_fields=['status'])
|
||||||
try:
|
|
||||||
order.send_mail(
|
for position in order.positions.all():
|
||||||
email_subject, email_template, email_context,
|
if position.voucher:
|
||||||
'pretix.event.order.email.order_canceled', user
|
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
||||||
)
|
|
||||||
except SendMailException:
|
order.log_action('pretix.event.order.canceled', user=user, auth=api_token or oauth_application or device,
|
||||||
logger.exception('Order canceled email could not be sent')
|
data={'cancellation_fee': cancellation_fee})
|
||||||
|
|
||||||
|
if send_mail:
|
||||||
|
email_template = order.event.settings.mail_text_order_canceled
|
||||||
|
email_context = {
|
||||||
|
'event': order.event.name,
|
||||||
|
'code': order.code,
|
||||||
|
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||||
|
'order': order.code,
|
||||||
|
'secret': order.secret
|
||||||
|
})
|
||||||
|
}
|
||||||
|
with language(order.locale):
|
||||||
|
email_subject = _('Order canceled: %(code)s') % {'code': order.code}
|
||||||
|
try:
|
||||||
|
order.send_mail(
|
||||||
|
email_subject, email_template, email_context,
|
||||||
|
'pretix.event.order.email.order_canceled', user
|
||||||
|
)
|
||||||
|
except SendMailException:
|
||||||
|
logger.exception('Order canceled email could not be sent')
|
||||||
|
|
||||||
order_canceled.send(order.event, order=order)
|
|
||||||
return order.pk
|
return order.pk
|
||||||
|
|
||||||
|
|
||||||
@@ -567,7 +559,6 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
|||||||
meta_info: dict=None, sales_channel: str='web'):
|
meta_info: dict=None, sales_channel: str='web'):
|
||||||
fees, pf = _get_fees(positions, payment_provider, address, meta_info, event)
|
fees, pf = _get_fees(positions, payment_provider, address, meta_info, event)
|
||||||
total = sum([c.price for c in positions]) + sum([c.value for c in fees])
|
total = sum([c.price for c in positions]) + sum([c.value for c in fees])
|
||||||
p = None
|
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
order = Order(
|
order = Order(
|
||||||
@@ -601,7 +592,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
|||||||
fee.save()
|
fee.save()
|
||||||
|
|
||||||
if payment_provider and not order.require_approval:
|
if payment_provider and not order.require_approval:
|
||||||
p = order.payments.create(
|
order.payments.create(
|
||||||
state=OrderPayment.PAYMENT_STATE_CREATED,
|
state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||||
provider=payment_provider.identifier,
|
provider=payment_provider.identifier,
|
||||||
amount=total,
|
amount=total,
|
||||||
@@ -617,7 +608,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
|||||||
order.log_action('pretix.event.order.consent', data={'msg': msg})
|
order.log_action('pretix.event.order.consent', data={'msg': msg})
|
||||||
|
|
||||||
order_placed.send(event, order=order)
|
order_placed.send(event, order=order)
|
||||||
return order, p
|
return order
|
||||||
|
|
||||||
|
|
||||||
def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||||
@@ -649,12 +640,8 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
|||||||
if len(position_ids) != len(positions):
|
if len(position_ids) != len(positions):
|
||||||
raise OrderError(error_messages['internal'])
|
raise OrderError(error_messages['internal'])
|
||||||
_check_positions(event, now_dt, positions, address=addr)
|
_check_positions(event, now_dt, positions, address=addr)
|
||||||
order, payment = _create_order(event, email, positions, now_dt, pprov,
|
order = _create_order(event, email, positions, now_dt, pprov,
|
||||||
locale=locale, address=addr, meta_info=meta_info, sales_channel=sales_channel)
|
locale=locale, address=addr, meta_info=meta_info, sales_channel=sales_channel)
|
||||||
|
|
||||||
free_order_flow = payment and payment_provider == 'free' and order.total == Decimal('0.00')
|
|
||||||
if free_order_flow:
|
|
||||||
payment.confirm(send_mail=False, lock=False)
|
|
||||||
|
|
||||||
invoice = order.invoices.last() # Might be generated by plugin already
|
invoice = order.invoices.last() # Might be generated by plugin already
|
||||||
if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
|
if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
|
||||||
@@ -669,7 +656,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
|||||||
if order.require_approval:
|
if order.require_approval:
|
||||||
email_template = event.settings.mail_text_order_placed_require_approval
|
email_template = event.settings.mail_text_order_placed_require_approval
|
||||||
log_entry = 'pretix.event.order.email.order_placed_require_approval'
|
log_entry = 'pretix.event.order.email.order_placed_require_approval'
|
||||||
elif free_order_flow:
|
elif payment_provider == 'free':
|
||||||
email_template = event.settings.mail_text_order_free
|
email_template = event.settings.mail_text_order_free
|
||||||
log_entry = 'pretix.event.order.email.order_free'
|
log_entry = 'pretix.event.order.email.order_free'
|
||||||
else:
|
else:
|
||||||
@@ -1390,8 +1377,6 @@ class OrderChangeManager:
|
|||||||
if self.split_order:
|
if self.split_order:
|
||||||
self._notify_user(self.split_order)
|
self._notify_user(self.split_order)
|
||||||
|
|
||||||
order_changed.send(self.order.event, order=self.order)
|
|
||||||
|
|
||||||
def _clear_tickets_cache(self):
|
def _clear_tickets_cache(self):
|
||||||
CachedTicket.objects.filter(order_position__order=self.order).delete()
|
CachedTicket.objects.filter(order_position__order=self.order).delete()
|
||||||
CachedCombinedTicket.objects.filter(order=self.order).delete()
|
CachedCombinedTicket.objects.filter(order=self.order).delete()
|
||||||
|
|||||||
@@ -49,10 +49,6 @@ DEFAULTS = {
|
|||||||
'default': 'True',
|
'default': 'True',
|
||||||
'type': bool,
|
'type': bool,
|
||||||
},
|
},
|
||||||
'invoice_address_not_asked_free': {
|
|
||||||
'default': 'False',
|
|
||||||
'type': bool,
|
|
||||||
},
|
|
||||||
'invoice_name_required': {
|
'invoice_name_required': {
|
||||||
'default': 'False',
|
'default': 'False',
|
||||||
'type': bool,
|
'type': bool,
|
||||||
@@ -105,10 +101,6 @@ DEFAULTS = {
|
|||||||
'default': 'False',
|
'default': 'False',
|
||||||
'type': bool
|
'type': bool
|
||||||
},
|
},
|
||||||
'presale_has_ended_text': {
|
|
||||||
'default': '',
|
|
||||||
'type': LazyI18nString
|
|
||||||
},
|
|
||||||
'payment_explanation': {
|
'payment_explanation': {
|
||||||
'default': '',
|
'default': '',
|
||||||
'type': LazyI18nString
|
'type': LazyI18nString
|
||||||
|
|||||||
@@ -275,66 +275,6 @@ because an already-paid order has been split.
|
|||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
order_canceled = EventPluginSignal(
|
|
||||||
providing_args=["order"]
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
This signal is sent out every time an order is canceled. The order object is given
|
|
||||||
as the first argument.
|
|
||||||
|
|
||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
order_expired = EventPluginSignal(
|
|
||||||
providing_args=["order"]
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
This signal is sent out every time an order is marked as expired. The order object is given
|
|
||||||
as the first argument.
|
|
||||||
|
|
||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
order_modified = EventPluginSignal(
|
|
||||||
providing_args=["order"]
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
This signal is sent out every time an order's information is modified. The order object is given
|
|
||||||
as the first argument.
|
|
||||||
|
|
||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
order_changed = EventPluginSignal(
|
|
||||||
providing_args=["order"]
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
This signal is sent out every time an order's content is changed. The order object is given
|
|
||||||
as the first argument.
|
|
||||||
|
|
||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
order_approved = EventPluginSignal(
|
|
||||||
providing_args=["order"]
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
This signal is sent out every time an order is being approved. The order object is given
|
|
||||||
as the first argument.
|
|
||||||
|
|
||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
order_denied = EventPluginSignal(
|
|
||||||
providing_args=["order"]
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
This signal is sent out every time an order is being denied. The order object is given
|
|
||||||
as the first argument.
|
|
||||||
|
|
||||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
|
||||||
"""
|
|
||||||
|
|
||||||
logentry_display = EventPluginSignal(
|
logentry_display = EventPluginSignal(
|
||||||
providing_args=["logentry"]
|
providing_args=["logentry"]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "error.html" %}
|
{% extends "error.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Bad Request" %}{% endblock %}
|
{% block title %}{% trans "Bad Request" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<i class="fa fa-frown-o fa-fw big-icon"></i>
|
<i class="fa fa-frown-o fa-fw big-icon"></i>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "error.html" %}
|
{% extends "error.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Permission denied" %}{% endblock %}
|
{% block title %}{% trans "Permission denied" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<i class="fa fa-fw fa-lock big-icon"></i>
|
<i class="fa fa-fw fa-lock big-icon"></i>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "error.html" %}
|
{% extends "error.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Not found" %}{% endblock %}
|
{% block title %}{% trans "Not found" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<i class="fa fa-meh-o fa-fw big-icon"></i>
|
<i class="fa fa-meh-o fa-fw big-icon"></i>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "error.html" %}
|
{% extends "error.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Internal Server Error" %}{% endblock %}
|
{% block title %}{% trans "Internal Server Error" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<i class="fa fa-bolt big-icon fa-fw"></i>
|
<i class="fa fa-bolt big-icon fa-fw"></i>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "error.html" %}
|
{% extends "error.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Verification failed" %}{% endblock %}
|
{% block title %}{% trans "Verification failed" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<i class="fa fa-frown-o big-icon fa-fw"></i>
|
<i class="fa fa-frown-o big-icon fa-fw"></i>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load compress %}
|
{% load compress %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from django.utils import timezone
|
|||||||
from django.utils.translation.trans_real import DjangoTranslation
|
from django.utils.translation.trans_real import DjangoTranslation
|
||||||
from django.views.decorators.cache import cache_page
|
from django.views.decorators.cache import cache_page
|
||||||
from django.views.decorators.http import etag
|
from django.views.decorators.http import etag
|
||||||
from django.views.i18n import JavaScriptCatalog
|
from django.views.i18n import JavaScriptCatalog, render_javascript_catalog
|
||||||
|
|
||||||
# Yes, we want to regenerate this every time the module has been imported to
|
# Yes, we want to regenerate this every time the module has been imported to
|
||||||
# refresh the cache at least at every code deployment
|
# refresh the cache at least at every code deployment
|
||||||
@@ -21,5 +21,4 @@ js_info_dict = {
|
|||||||
def js_catalog(request, lang):
|
def js_catalog(request, lang):
|
||||||
c = JavaScriptCatalog()
|
c = JavaScriptCatalog()
|
||||||
c.translation = DjangoTranslation(lang, domain='djangojs')
|
c.translation = DjangoTranslation(lang, domain='djangojs')
|
||||||
context = c.get_context_data()
|
return render_javascript_catalog(c.get_catalog(), c.get_plural())
|
||||||
return c.render_to_response(context)
|
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ def serve_metrics(request):
|
|||||||
return unauthed_response()
|
return unauthed_response()
|
||||||
|
|
||||||
# check if the user is properly authorized:
|
# check if the user is properly authorized:
|
||||||
if "Authorization" not in request.headers:
|
if "HTTP_AUTHORIZATION" not in request.META:
|
||||||
return unauthed_response()
|
return unauthed_response()
|
||||||
|
|
||||||
method, credentials = request.headers["Authorization"].split(" ", 1)
|
method, credentials = request.META["HTTP_AUTHORIZATION"].split(" ", 1)
|
||||||
if method.lower() != "basic":
|
if method.lower() != "basic":
|
||||||
return unauthed_response()
|
return unauthed_response()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.files.uploadedfile import UploadedFile
|
from django.core.files.uploadedfile import UploadedFile
|
||||||
@@ -187,35 +186,25 @@ class OrderQuestionsViewMixin(BaseQuestionsViewMixin):
|
|||||||
except InvoiceAddress.DoesNotExist:
|
except InvoiceAddress.DoesNotExist:
|
||||||
return InvoiceAddress(order=self.order)
|
return InvoiceAddress(order=self.order)
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def address_asked(self):
|
|
||||||
return self.request.event.settings.invoice_address_asked and (
|
|
||||||
self.order.total != Decimal('0.00') or not self.request.event.settings.invoice_address_not_asked_free
|
|
||||||
)
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def invoice_form(self):
|
def invoice_form(self):
|
||||||
if not self.address_asked and self.request.event.settings.invoice_name_required:
|
if not self.request.event.settings.invoice_address_asked and self.request.event.settings.invoice_name_required:
|
||||||
return self.invoice_name_form_class(
|
return self.invoice_name_form_class(
|
||||||
data=self.request.POST if self.request.method == "POST" else None,
|
data=self.request.POST if self.request.method == "POST" else None,
|
||||||
event=self.request.event,
|
event=self.request.event,
|
||||||
instance=self.invoice_address, validate_vat_id=False,
|
instance=self.invoice_address, validate_vat_id=False,
|
||||||
all_optional=self.all_optional
|
all_optional=self.all_optional
|
||||||
)
|
)
|
||||||
if self.address_asked:
|
return self.invoice_form_class(
|
||||||
return self.invoice_form_class(
|
data=self.request.POST if self.request.method == "POST" else None,
|
||||||
data=self.request.POST if self.request.method == "POST" else None,
|
event=self.request.event,
|
||||||
event=self.request.event,
|
instance=self.invoice_address, validate_vat_id=False,
|
||||||
instance=self.invoice_address, validate_vat_id=False,
|
all_optional=self.all_optional,
|
||||||
all_optional=self.all_optional,
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
return forms.Form(data=self.request.POST if self.request.method == "POST" else None)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
ctx['order'] = self.order
|
ctx['order'] = self.order
|
||||||
ctx['formgroups'] = self.formdict.items()
|
ctx['formgroups'] = self.formdict.items()
|
||||||
ctx['invoice_form'] = self.invoice_form
|
ctx['invoice_form'] = self.invoice_form
|
||||||
ctx['invoice_address_asked'] = self.address_asked
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|||||||
@@ -621,10 +621,6 @@ class InvoiceSettingsForm(SettingsForm):
|
|||||||
widget=forms.CheckboxInput(attrs={'data-checkbox-dependency': '#id_invoice_address_asked'}),
|
widget=forms.CheckboxInput(attrs={'data-checkbox-dependency': '#id_invoice_address_asked'}),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
invoice_address_not_asked_free = forms.BooleanField(
|
|
||||||
label=_('Do not ask for invoice address if an order is free'),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
invoice_include_free = forms.BooleanField(
|
invoice_include_free = forms.BooleanField(
|
||||||
label=_("Show free products on invoices"),
|
label=_("Show free products on invoices"),
|
||||||
help_text=_("Note that invoices will never be generated for orders that contain only free "
|
help_text=_("Note that invoices will never be generated for orders that contain only free "
|
||||||
@@ -1053,14 +1049,6 @@ class DisplaySettingsForm(SettingsForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=I18nTextarea
|
widget=I18nTextarea
|
||||||
)
|
)
|
||||||
presale_has_ended_text = I18nFormField(
|
|
||||||
label=_("End of presale text"),
|
|
||||||
required=False,
|
|
||||||
widget=I18nTextarea,
|
|
||||||
widget_kwargs={'attrs': {'rows': '2'}},
|
|
||||||
help_text=_("This text will be shown above the ticket shop once the designated sales timeframe for this event "
|
|
||||||
"is over. You can use it to describe other options to get a ticket, such as a box office.")
|
|
||||||
)
|
|
||||||
voucher_explanation_text = I18nFormField(
|
voucher_explanation_text = I18nFormField(
|
||||||
label=_("Voucher explanation"),
|
label=_("Voucher explanation"),
|
||||||
required=False,
|
required=False,
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
|
import dateutil
|
||||||
|
import pytz
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models import Max
|
from django.db.models import Max
|
||||||
from django.forms.formsets import DELETION_FIELD_NAME
|
from django.forms.formsets import DELETION_FIELD_NAME
|
||||||
|
from django.forms.utils import from_current_timezone, to_current_timezone
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils import formats
|
||||||
from django.utils.translation import (
|
from django.utils.translation import (
|
||||||
pgettext_lazy, ugettext as __, ugettext_lazy as _,
|
pgettext_lazy, ugettext as __, ugettext_lazy as _,
|
||||||
)
|
)
|
||||||
@@ -33,6 +39,63 @@ class CategoryForm(I18nModelForm):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class AdjustableTypeField(forms.Textarea):
|
||||||
|
def __init__(self, *args, type=None, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def format_value(self, value):
|
||||||
|
if getattr(self, 'type') == 'W' and value:
|
||||||
|
return str(formats.localize_input(to_current_timezone(dateutil.parser.parse(value))))
|
||||||
|
elif getattr(self, 'type') == 'D' and value:
|
||||||
|
return str(formats.localize_input(dateutil.parser.parse(value).date()))
|
||||||
|
elif getattr(self, 'type') == 'T' and value:
|
||||||
|
return str(formats.localize_input(dateutil.parser.parse(value).time()))
|
||||||
|
return super().format_value(value)
|
||||||
|
|
||||||
|
def value_from_datadict(self, data, files, name):
|
||||||
|
if 'type' in data and data['type'] == 'W' and 'default_value_date' in data and 'default_value_time' in data:
|
||||||
|
d_date = d_time = None
|
||||||
|
|
||||||
|
for format in formats.get_format('DATE_INPUT_FORMATS'):
|
||||||
|
try:
|
||||||
|
d_date = datetime.datetime.strptime(data['default_value_date'], format).date()
|
||||||
|
break
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for format in formats.get_format('TIME_INPUT_FORMATS'):
|
||||||
|
try:
|
||||||
|
d_time = datetime.datetime.strptime(data['default_value_time'], format).time()
|
||||||
|
break
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if d_date and d_time:
|
||||||
|
return from_current_timezone(datetime.datetime.combine(d_date, d_time)).astimezone(pytz.UTC).isoformat()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
val = super().value_from_datadict(data, files, name)
|
||||||
|
if 'type' in data and data['type'] == 'D' and val:
|
||||||
|
for format in formats.get_format('DATE_INPUT_FORMATS'):
|
||||||
|
try:
|
||||||
|
d_date = datetime.datetime.strptime(val, format).date()
|
||||||
|
val = d_date.isoformat()
|
||||||
|
break
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
continue
|
||||||
|
elif 'type' in data and data['type'] == 'T' and val:
|
||||||
|
for format in formats.get_format('TIME_INPUT_FORMATS'):
|
||||||
|
try:
|
||||||
|
d_date = datetime.datetime.strptime(val, format).time()
|
||||||
|
val = d_date.isoformat()
|
||||||
|
break
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
class QuestionForm(I18nModelForm):
|
class QuestionForm(I18nModelForm):
|
||||||
question = I18nFormField(
|
question = I18nFormField(
|
||||||
label=_("Question"),
|
label=_("Question"),
|
||||||
@@ -43,7 +106,6 @@ class QuestionForm(I18nModelForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields['items'].queryset = self.instance.event.items.all()
|
self.fields['items'].queryset = self.instance.event.items.all()
|
||||||
self.fields['items'].required = True
|
|
||||||
self.fields['dependency_question'].queryset = self.instance.event.questions.filter(
|
self.fields['dependency_question'].queryset = self.instance.event.questions.filter(
|
||||||
type__in=(Question.TYPE_BOOLEAN, Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE)
|
type__in=(Question.TYPE_BOOLEAN, Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE)
|
||||||
)
|
)
|
||||||
@@ -52,6 +114,8 @@ class QuestionForm(I18nModelForm):
|
|||||||
pk=self.instance.pk
|
pk=self.instance.pk
|
||||||
)
|
)
|
||||||
self.fields['identifier'].required = False
|
self.fields['identifier'].required = False
|
||||||
|
if self.instance:
|
||||||
|
self.fields['default_value'].widget.type = self.instance.type
|
||||||
self.fields['help_text'].widget.attrs['rows'] = 3
|
self.fields['help_text'].widget.attrs['rows'] = 3
|
||||||
|
|
||||||
def clean_dependency_question(self):
|
def clean_dependency_question(self):
|
||||||
@@ -81,6 +145,7 @@ class QuestionForm(I18nModelForm):
|
|||||||
'help_text',
|
'help_text',
|
||||||
'type',
|
'type',
|
||||||
'required',
|
'required',
|
||||||
|
'default_value',
|
||||||
'ask_during_checkin',
|
'ask_during_checkin',
|
||||||
'identifier',
|
'identifier',
|
||||||
'items',
|
'items',
|
||||||
@@ -91,7 +156,8 @@ class QuestionForm(I18nModelForm):
|
|||||||
'items': forms.CheckboxSelectMultiple(
|
'items': forms.CheckboxSelectMultiple(
|
||||||
attrs={'class': 'scrolling-multiple-choice'}
|
attrs={'class': 'scrolling-multiple-choice'}
|
||||||
),
|
),
|
||||||
'dependency_value': forms.Select,
|
'default_value': AdjustableTypeField(),
|
||||||
|
'dependency_value': forms.Select
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load compress %}
|
{% load compress %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|||||||
+6
-12
@@ -1,15 +1,11 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<dl class="dl-horizontal">
|
{% if payment_info %}
|
||||||
<dt>{% trans "Device ID" %}</dt>
|
<dl class="dl-horizontal">
|
||||||
<dd>{{ payment_info.pos_id }}</dd>
|
|
||||||
<dt>{% trans "Receipt ID" %}</dt>
|
|
||||||
<dd>{{ payment_info.receipt_id }}</dd>
|
|
||||||
{% if payment_info.payment_type == "sumup" %}
|
|
||||||
<dt>{% trans "Payment provider" %}</dt>
|
<dt>{% trans "Payment provider" %}</dt>
|
||||||
<dd>SumUp</dd>
|
<dd>SumUp</dd>
|
||||||
<dt>{% trans "Transaction Code" %}</dt>
|
<dt>{% trans "Transaction Code" %}</dt>
|
||||||
<dd>{{ payment_info.payment_data.tx_code }}</dd>
|
<dd>{{ payment_info.payment_data.tx_code}}</dd>
|
||||||
<dt>{% trans "Merchant Code" %}</dt>
|
<dt>{% trans "Merchant Code" %}</dt>
|
||||||
<dd>{{ payment_info.payment_data.merchant_code }}</dd>
|
<dd>{{ payment_info.payment_data.merchant_code }}</dd>
|
||||||
<dt>{% trans "Currency" %}</dt>
|
<dt>{% trans "Currency" %}</dt>
|
||||||
@@ -21,8 +17,6 @@
|
|||||||
<dt>{% trans "Card Entry Mode" %}</dt>
|
<dt>{% trans "Card Entry Mode" %}</dt>
|
||||||
<dd>{{ payment_info.payment_data.entry_mode }}</dd>
|
<dd>{{ payment_info.payment_data.entry_mode }}</dd>
|
||||||
<dt>{% trans "Card number" %}</dt>
|
<dt>{% trans "Card number" %}</dt>
|
||||||
<dd>
|
<dd><i class="fa fa-cc-{{ payment_info.payment_data.card_type|lower }}"></i> **** **** **** {{ payment_info.payment_data.last4 }}</dd>
|
||||||
<i class="fa fa-cc-{{ payment_info.payment_data.card_type|lower }}"></i> **** **** **** {{ payment_info.payment_data.last4 }}
|
</dl>
|
||||||
</dd>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</dl>
|
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
<legend>{% trans "Event page" %}</legend>
|
<legend>{% trans "Event page" %}</legend>
|
||||||
{% bootstrap_field form.logo_image layout="control" %}
|
{% bootstrap_field form.logo_image layout="control" %}
|
||||||
{% bootstrap_field form.frontpage_text layout="control" %}
|
{% bootstrap_field form.frontpage_text layout="control" %}
|
||||||
{% bootstrap_field form.presale_has_ended_text layout="control" %}
|
|
||||||
{% bootstrap_field form.voucher_explanation_text layout="control" %}
|
{% bootstrap_field form.voucher_explanation_text layout="control" %}
|
||||||
{% bootstrap_field form.show_variations_expanded layout="control" %}
|
{% bootstrap_field form.show_variations_expanded layout="control" %}
|
||||||
{% bootstrap_field form.meta_noindex layout="control" %}
|
{% bootstrap_field form.meta_noindex layout="control" %}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
{% bootstrap_field form.invoice_address_company_required layout="control" %}
|
{% bootstrap_field form.invoice_address_company_required layout="control" %}
|
||||||
{% bootstrap_field form.invoice_address_vatid layout="control" %}
|
{% bootstrap_field form.invoice_address_vatid layout="control" %}
|
||||||
{% bootstrap_field form.invoice_address_beneficiary layout="control" %}
|
{% bootstrap_field form.invoice_address_beneficiary layout="control" %}
|
||||||
{% bootstrap_field form.invoice_address_not_asked_free layout="control" %}
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Your invoice details" %}</legend>
|
<legend>{% trans "Your invoice details" %}</legend>
|
||||||
|
|||||||
@@ -107,6 +107,7 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Advanced settings" %}</legend>
|
<legend>{% trans "Advanced settings" %}</legend>
|
||||||
{% bootstrap_field form.help_text layout="control" %}
|
{% bootstrap_field form.help_text layout="control" %}
|
||||||
|
{% bootstrap_field form.default_value layout="control" %}
|
||||||
{% bootstrap_field form.identifier layout="control" %}
|
{% bootstrap_field form.identifier layout="control" %}
|
||||||
{% bootstrap_field form.ask_during_checkin layout="control" %}
|
{% bootstrap_field form.ask_during_checkin layout="control" %}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<form method="post" class="form-horizontal" href="" enctype="multipart/form-data">
|
<form method="post" class="form-horizontal" href="" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="panel-group" id="questions_accordion">
|
<div class="panel-group" id="questions_accordion">
|
||||||
{% if invoice_address_asked or order.invoice_address or request.event.settings.invoice_name_required %}
|
{% if request.event.settings.invoice_address_asked or order.invoice_address or request.event.settings.invoice_name_required %}
|
||||||
<details class="panel panel-default" open>
|
<details class="panel panel-default" open>
|
||||||
<summary class="panel-heading">
|
<summary class="panel-heading">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "pretixcontrol/organizers/base.html" %}
|
{% extends "pretixcontrol/organizers/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load staticfiles %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block inner %}
|
{% block inner %}
|
||||||
<h1>{% trans "Connect to device:" %} {{ device.name }}</h1>
|
<h1>{% trans "Connect to device:" %} {{ device.name }}</h1>
|
||||||
|
|||||||
@@ -9,13 +9,6 @@
|
|||||||
<strong>{% blocktrans %}Are you sure you want remove access for this device?{% endblocktrans %}</strong>
|
<strong>{% blocktrans %}Are you sure you want remove access for this device?{% endblocktrans %}</strong>
|
||||||
{% trans "All data of this device will stay available, but you can't use the device any more." %}
|
{% trans "All data of this device will stay available, but you can't use the device any more." %}
|
||||||
</p>
|
</p>
|
||||||
<div class="alert alert-warning">
|
|
||||||
<ul>
|
|
||||||
<li>{% trans "All data uploaded by this device will stay available online." %}</li>
|
|
||||||
<li>{% trans "If data (e.g. POS transactions or check-ins) has been created on this device and has not been uploaded, you will no longer be able to upload it." %}</li>
|
|
||||||
<li>{% trans "If the device software supports it, personal data such as orders will be deleted from the device on the next synchronization attempt. Non-personal data such as event metadata and POS transactions will persist until you uninstall or reset the software manually." %}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="form-group submit-group">
|
<div class="form-group submit-group">
|
||||||
<a href="{% url "control:organizer.devices" organizer=request.organizer.slug %}" class="btn btn-default btn-cancel">
|
<a href="{% url "control:organizer.devices" organizer=request.organizer.slug %}" class="btn btn-default btn-cancel">
|
||||||
{% trans "Cancel" %}
|
{% trans "Cancel" %}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ from django.views.generic.edit import DeleteView
|
|||||||
|
|
||||||
from pretix.base.forms import I18nFormSet
|
from pretix.base.forms import I18nFormSet
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CachedTicket, CartPosition, Item, ItemCategory, ItemVariation, Order,
|
CachedTicket, Item, ItemCategory, ItemVariation, Order, Question,
|
||||||
Question, QuestionAnswer, QuestionOption, Quota, Voucher,
|
QuestionAnswer, QuestionOption, Quota, Voucher,
|
||||||
)
|
)
|
||||||
from pretix.base.models.event import SubEvent
|
from pretix.base.models.event import SubEvent
|
||||||
from pretix.base.models.items import ItemAddOn, ItemBundle
|
from pretix.base.models.items import ItemAddOn, ItemBundle
|
||||||
@@ -49,9 +49,7 @@ class ItemList(ListView):
|
|||||||
event=self.request.event
|
event=self.request.event
|
||||||
).annotate(
|
).annotate(
|
||||||
var_count=Count('variations')
|
var_count=Count('variations')
|
||||||
).prefetch_related("category").order_by(
|
).prefetch_related("category")
|
||||||
'category__position', 'category', 'position'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def item_move(request, item, up=True):
|
def item_move(request, item, up=True):
|
||||||
@@ -1160,7 +1158,6 @@ class ItemDelete(EventPermissionRequiredMixin, DeleteView):
|
|||||||
success_url = self.get_success_url()
|
success_url = self.get_success_url()
|
||||||
o = self.get_object()
|
o = self.get_object()
|
||||||
if o.allow_delete():
|
if o.allow_delete():
|
||||||
CartPosition.objects.filter(addon_to__item=self.get_object()).delete()
|
|
||||||
self.get_object().cartposition_set.all().delete()
|
self.get_object().cartposition_set.all().delete()
|
||||||
self.get_object().log_action('pretix.event.item.deleted', user=self.request.user)
|
self.get_object().log_action('pretix.event.item.deleted', user=self.request.user)
|
||||||
self.get_object().delete()
|
self.get_object().delete()
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ from pretix.base.services.orders import (
|
|||||||
from pretix.base.services.stats import order_overview
|
from pretix.base.services.stats import order_overview
|
||||||
from pretix.base.services.tickets import generate
|
from pretix.base.services.tickets import generate
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
order_modified, register_data_exporters, register_ticket_outputs,
|
register_data_exporters, register_ticket_outputs,
|
||||||
)
|
)
|
||||||
from pretix.base.templatetags.money import money_filter
|
from pretix.base.templatetags.money import money_filter
|
||||||
from pretix.base.templatetags.rich_text import markdown_compile_email
|
from pretix.base.templatetags.rich_text import markdown_compile_email
|
||||||
@@ -1305,8 +1305,7 @@ class OrderModifyInformation(OrderQuestionsViewMixin, OrderView):
|
|||||||
messages.error(self.request,
|
messages.error(self.request,
|
||||||
_("We had difficulties processing your input. Please review the errors below."))
|
_("We had difficulties processing your input. Please review the errors below."))
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
if hasattr(self.invoice_form, 'save'):
|
self.invoice_form.save()
|
||||||
self.invoice_form.save()
|
|
||||||
self.order.log_action('pretix.event.order.modified', {
|
self.order.log_action('pretix.event.order.modified', {
|
||||||
'invoice_data': self.invoice_form.cleaned_data,
|
'invoice_data': self.invoice_form.cleaned_data,
|
||||||
'data': [{
|
'data': [{
|
||||||
@@ -1321,8 +1320,6 @@ class OrderModifyInformation(OrderQuestionsViewMixin, OrderView):
|
|||||||
|
|
||||||
CachedTicket.objects.filter(order_position__order=self.order).delete()
|
CachedTicket.objects.filter(order_position__order=self.order).delete()
|
||||||
CachedCombinedTicket.objects.filter(order=self.order).delete()
|
CachedCombinedTicket.objects.filter(order=self.order).delete()
|
||||||
|
|
||||||
order_modified.send(sender=self.request.event, order=self.order)
|
|
||||||
return redirect(self.get_order_url())
|
return redirect(self.get_order_url())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -756,7 +756,7 @@ class DeviceRevokeView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
|
|||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
self.object.revoked = True
|
self.object.api_token = None
|
||||||
self.object.save()
|
self.object.save()
|
||||||
self.object.log_action('pretix.device.revoked', user=self.request.user)
|
self.object.log_action('pretix.device.revoked', user=self.request.user)
|
||||||
messages.success(request, _('Access for this device has been revoked.'))
|
messages.success(request, _('Access for this device has been revoked.'))
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
|
|||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||||
|
|
||||||
from pretix.base.models import CartPosition
|
|
||||||
from pretix.base.models.checkin import CheckinList
|
from pretix.base.models.checkin import CheckinList
|
||||||
from pretix.base.models.event import SubEvent, SubEventMetaValue
|
from pretix.base.models.event import SubEvent, SubEventMetaValue
|
||||||
from pretix.base.models.items import (
|
from pretix.base.models.items import (
|
||||||
@@ -118,7 +117,6 @@ class SubEventDelete(EventPermissionRequiredMixin, DeleteView):
|
|||||||
return HttpResponseRedirect(self.get_success_url())
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
else:
|
else:
|
||||||
self.object.log_action('pretix.subevent.deleted', user=self.request.user)
|
self.object.log_action('pretix.subevent.deleted', user=self.request.user)
|
||||||
CartPosition.objects.filter(addon_to__subevent=self.object).delete()
|
|
||||||
self.object.cartposition_set.all().delete()
|
self.object.cartposition_set.all().delete()
|
||||||
self.object.delete()
|
self.object.delete()
|
||||||
messages.success(request, pgettext_lazy('subevent', 'The selected date has been deleted.'))
|
messages.success(request, pgettext_lazy('subevent', 'The selected date has been deleted.'))
|
||||||
@@ -514,7 +512,6 @@ class SubEventBulkAction(EventPermissionRequiredMixin, View):
|
|||||||
elif request.POST.get('action') == 'delete_confirm':
|
elif request.POST.get('action') == 'delete_confirm':
|
||||||
for obj in self.objects:
|
for obj in self.objects:
|
||||||
if obj.allow_delete():
|
if obj.allow_delete():
|
||||||
CartPosition.objects.filter(addon_to__subevent=obj).delete()
|
|
||||||
obj.cartposition_set.all().delete()
|
obj.cartposition_set.all().delete()
|
||||||
obj.log_action('pretix.subevent.deleted', user=self.request.user)
|
obj.log_action('pretix.subevent.deleted', user=self.request.user)
|
||||||
obj.delete()
|
obj.delete()
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from django.views.generic import (
|
|||||||
CreateView, DeleteView, ListView, TemplateView, UpdateView, View,
|
CreateView, DeleteView, ListView, TemplateView, UpdateView, View,
|
||||||
)
|
)
|
||||||
|
|
||||||
from pretix.base.models import CartPosition, LogEntry, OrderPosition, Voucher
|
from pretix.base.models import LogEntry, Voucher
|
||||||
from pretix.base.models.vouchers import _generate_random_code
|
from pretix.base.models.vouchers import _generate_random_code
|
||||||
from pretix.control.forms.filter import VoucherFilterForm
|
from pretix.control.forms.filter import VoucherFilterForm
|
||||||
from pretix.control.forms.vouchers import VoucherBulkForm, VoucherForm
|
from pretix.control.forms.vouchers import VoucherBulkForm, VoucherForm
|
||||||
@@ -143,7 +143,6 @@ class VoucherDelete(EventPermissionRequiredMixin, DeleteView):
|
|||||||
messages.error(request, _('A voucher can not be deleted if it already has been redeemed.'))
|
messages.error(request, _('A voucher can not be deleted if it already has been redeemed.'))
|
||||||
else:
|
else:
|
||||||
self.object.log_action('pretix.voucher.deleted', user=self.request.user)
|
self.object.log_action('pretix.voucher.deleted', user=self.request.user)
|
||||||
CartPosition.objects.filter(addon_to__voucher=False).delete()
|
|
||||||
self.object.cartposition_set.all().delete()
|
self.object.cartposition_set.all().delete()
|
||||||
self.object.delete()
|
self.object.delete()
|
||||||
messages.success(request, _('The selected voucher has been deleted.'))
|
messages.success(request, _('The selected voucher has been deleted.'))
|
||||||
@@ -349,7 +348,6 @@ class VoucherBulkAction(EventPermissionRequiredMixin, View):
|
|||||||
for obj in self.objects:
|
for obj in self.objects:
|
||||||
if obj.allow_delete():
|
if obj.allow_delete():
|
||||||
obj.log_action('pretix.voucher.deleted', user=self.request.user)
|
obj.log_action('pretix.voucher.deleted', user=self.request.user)
|
||||||
OrderPosition.objects.filter(addon_to__voucher=obj).delete()
|
|
||||||
obj.cartposition_set.all().delete()
|
obj.cartposition_set.all().delete()
|
||||||
obj.delete()
|
obj.delete()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class SessionReauthRequired(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def get_user_agent_hash(request):
|
def get_user_agent_hash(request):
|
||||||
return hashlib.sha256(request.headers['User-Agent'].encode()).hexdigest()
|
return hashlib.sha256(request.META['HTTP_USER_AGENT'].encode()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def assert_session_valid(request):
|
def assert_session_valid(request):
|
||||||
@@ -26,7 +26,7 @@ def assert_session_valid(request):
|
|||||||
if time.time() - last_used > settings.PRETIX_SESSION_TIMEOUT_RELATIVE:
|
if time.time() - last_used > settings.PRETIX_SESSION_TIMEOUT_RELATIVE:
|
||||||
raise SessionReauthRequired()
|
raise SessionReauthRequired()
|
||||||
|
|
||||||
if 'User-Agent' in request.headers:
|
if 'HTTP_USER_AGENT' in request.META:
|
||||||
if 'pinned_user_agent' in request.session:
|
if 'pinned_user_agent' in request.session:
|
||||||
if request.session.get('pinned_user_agent') != get_user_agent_hash(request):
|
if request.session.get('pinned_user_agent') != get_user_agent_hash(request):
|
||||||
raise SessionInvalid()
|
raise SessionInvalid()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Automatically generated\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,465 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
||||||
"Last-Translator: Automatically generated\n"
|
|
||||||
"Language-Team: none\n"
|
|
||||||
"Language: ca\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"
|
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:68
|
|
||||||
msgid "Marked as paid"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:76
|
|
||||||
msgid "Comment:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
|
||||||
msgid "Placed orders"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
|
||||||
msgid "Paid orders"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
|
||||||
msgid "Total revenue"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:12
|
|
||||||
msgid "Contacting Stripe …"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
|
||||||
msgid "Total"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
|
||||||
msgid ""
|
|
||||||
"Your request has been queued on the server and will now be processed. "
|
|
||||||
"Depending on the size of your event, this might take up to a few minutes."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
|
||||||
msgid ""
|
|
||||||
"Your request arrived on the server but we still wait for it to be processed. "
|
|
||||||
"If this takes longer than two minutes, please contact us or go back in your "
|
|
||||||
"browser and try again."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
|
||||||
msgid "An error of type {code} occurred."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
|
||||||
msgid ""
|
|
||||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
|
||||||
"{code}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
|
||||||
msgid "The request took to long. Please try again."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
|
||||||
msgid ""
|
|
||||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
|
||||||
msgid "We are processing your request …"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
|
||||||
msgid ""
|
|
||||||
"We are currently sending your request to the server. If this takes longer "
|
|
||||||
"than one minute, please check your internet connection and then reload this "
|
|
||||||
"page and try again."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
|
||||||
msgid "Close message"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/clipboard.js:23
|
|
||||||
msgid "Copied!"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/clipboard.js:29
|
|
||||||
msgid "Press Ctrl-C to copy!"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:43
|
|
||||||
msgid "Lead Scan QR"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:45
|
|
||||||
msgid "Check-in QR"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:249
|
|
||||||
msgid "The PDF background file could not be loaded for the following reason:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:418
|
|
||||||
msgid "Group of objects"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:424
|
|
||||||
msgid "Text object"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:426
|
|
||||||
msgid "Barcode area"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:428
|
|
||||||
msgid "Powered by pretix"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:430
|
|
||||||
msgid "Object"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:434
|
|
||||||
msgid "Ticket design"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:687
|
|
||||||
msgid "Saving failed."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:735
|
|
||||||
msgid "Do you really want to leave the editor without saving your changes?"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:749
|
|
||||||
msgid "Error while uploading your PDF file, please try again."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/mail.js:18
|
|
||||||
msgid "An error has occurred."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/mail.js:52
|
|
||||||
msgid "Generating messages …"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
|
||||||
msgid "Unknown error."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
|
||||||
msgid "Your color has great contrast and is very easy to read!"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
|
||||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
|
||||||
msgid ""
|
|
||||||
"Your color has bad contrast for text on white background, please choose a "
|
|
||||||
"darker shade."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
|
||||||
msgid "All"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:307
|
|
||||||
msgid "None"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
|
||||||
msgid "Use a different name internally"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:646
|
|
||||||
msgid "Click to close"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:42
|
|
||||||
msgid "Others"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:71
|
|
||||||
msgid "Count"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
|
||||||
msgid "Yes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
|
||||||
msgid "No"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
|
||||||
msgid "(one more date)"
|
|
||||||
msgid_plural "({num} more dates)"
|
|
||||||
msgstr[0] ""
|
|
||||||
msgstr[1] ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/cart.js:39
|
|
||||||
msgid "The items in your cart are no longer reserved for you."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/cart.js:41
|
|
||||||
msgid "Cart expired"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/cart.js:46
|
|
||||||
msgid "The items in your cart are reserved for you for one minute."
|
|
||||||
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
|
||||||
msgstr[0] ""
|
|
||||||
msgstr[1] ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:14
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Sold out"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:15
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Buy"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:16
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Reserved"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:17
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "FREE"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:18
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "from %(currency)s %(price)s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:19
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "incl. %(rate)s% %(taxname)s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "plus %(rate)s% %(taxname)s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "incl. taxes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "plus taxes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
|
||||||
#, javascript-format
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "currently available: %s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:24
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Only available with a voucher"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:25
|
|
||||||
#, javascript-format
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "minimum amount to order: %s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:26
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Close ticket shop"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:27
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "The ticket shop could not be loaded."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:28
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "The cart could not be created. Please try again later"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:29
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Waiting list"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:30
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid ""
|
|
||||||
"You currently have an active cart for this event. If you select more "
|
|
||||||
"products, they will be added to your existing cart."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:32
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Resume checkout"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:33
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid ""
|
|
||||||
"<a href=\"https://pretix.eu\" target=\"_blank\" rel=\"noopener\">event "
|
|
||||||
"ticketing powered by pretix</a>"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:35
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Redeem a voucher"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:36
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Redeem"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:37
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Voucher code"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:38
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Close"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:39
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Continue"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:40
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "See variations"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Choose a different event"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Back"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Next month"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
|
||||||
msgctxt "widget"
|
|
||||||
msgid "Previous month"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
|
||||||
msgid "Mo"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
|
||||||
msgid "Tu"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
|
||||||
msgid "We"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
|
||||||
msgid "Th"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
|
||||||
msgid "Fr"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
|
||||||
msgid "Sa"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
|
||||||
msgid "Su"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
|
||||||
msgid "January"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
|
||||||
msgid "February"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
|
||||||
msgid "March"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
|
||||||
msgid "April"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
|
||||||
msgid "May"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
|
||||||
msgid "June"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
|
||||||
msgid "July"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
|
||||||
msgid "August"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
|
||||||
msgid "September"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
|
||||||
msgid "October"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
|
||||||
msgid "November"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
|
||||||
msgid "December"
|
|
||||||
msgstr ""
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Automatically generated\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2018-04-24 14:22+0000\n"
|
"PO-Revision-Date: 2018-04-24 14:22+0000\n"
|
||||||
"Last-Translator: Pernille Thorsen <perth@aarhus.dk>\n"
|
"Last-Translator: Pernille Thorsen <perth@aarhus.dk>\n"
|
||||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-22 15:00+0000\n"
|
"PO-Revision-Date: 2019-03-22 15:00+0000\n"
|
||||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-22 15:00+0000\n"
|
"PO-Revision-Date: 2019-03-22 15:00+0000\n"
|
||||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||||
|
|||||||
+294
-347
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Automatically generated\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-31 08:00+0000\n"
|
"PO-Revision-Date: 2019-02-20 03:00+0000\n"
|
||||||
"Last-Translator: oocf <oswaldocerna@gmail.com>\n"
|
"Last-Translator: oocf <oswaldocerna@gmail.com>\n"
|
||||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
|
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||||
"js/es/>\n"
|
"js/es/>\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 3.5.1\n"
|
"X-Generator: Weblate 3.4\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -220,7 +220,7 @@ msgstr "Usar un nombre diferente internamente"
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:646
|
#: pretix/static/pretixcontrol/js/ui/main.js:646
|
||||||
msgid "Click to close"
|
msgid "Click to close"
|
||||||
msgstr "Click para cerrar"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:42
|
#: pretix/static/pretixcontrol/js/ui/question.js:42
|
||||||
msgid "Others"
|
msgid "Others"
|
||||||
@@ -232,11 +232,13 @@ msgstr "Cantidad"
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Si"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "None"
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "No"
|
msgstr "Ninguno"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
||||||
msgid "(one more date)"
|
msgid "(one more date)"
|
||||||
@@ -298,12 +300,12 @@ msgstr "más %(rate)s% %(taxname)s"
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "incl. taxes"
|
msgid "incl. taxes"
|
||||||
msgstr "incl. impuestos"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "plus taxes"
|
msgid "plus taxes"
|
||||||
msgstr "más impuestos"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
@@ -398,100 +400,102 @@ msgid "See variations"
|
|||||||
msgstr "Ver variaciones"
|
msgstr "Ver variaciones"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Use a different name internally"
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Choose a different event"
|
msgid "Choose a different event"
|
||||||
msgstr "Elige un evento diferente"
|
msgstr "Usar un nombre diferente internamente"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Atrás"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Next month"
|
msgid "Next month"
|
||||||
msgstr "Siguiente mes"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Previous month"
|
msgid "Previous month"
|
||||||
msgstr "Mes anterior"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
||||||
msgid "Mo"
|
msgid "Mo"
|
||||||
msgstr "Me"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
||||||
msgid "Tu"
|
msgid "Tu"
|
||||||
msgstr "Ma"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
||||||
msgid "We"
|
msgid "We"
|
||||||
msgstr "Mie"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
||||||
msgid "Th"
|
msgid "Th"
|
||||||
msgstr "Ju"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
||||||
msgid "Fr"
|
msgid "Fr"
|
||||||
msgstr "Vi"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
||||||
msgid "Sa"
|
msgid "Sa"
|
||||||
msgstr "Sá"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
||||||
msgid "Su"
|
msgid "Su"
|
||||||
msgstr "Do"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
||||||
msgid "January"
|
msgid "January"
|
||||||
msgstr "Enero"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
||||||
msgid "February"
|
msgid "February"
|
||||||
msgstr "Febrero"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
||||||
msgid "March"
|
msgid "March"
|
||||||
msgstr "Marzo"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
||||||
msgid "April"
|
msgid "April"
|
||||||
msgstr "Abril"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
||||||
msgid "May"
|
msgid "May"
|
||||||
msgstr "Mayo"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
||||||
msgid "June"
|
msgid "June"
|
||||||
msgstr "Junio"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
||||||
msgid "July"
|
msgid "July"
|
||||||
msgstr "Julio"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
||||||
msgid "August"
|
msgid "August"
|
||||||
msgstr "Agosto"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
||||||
msgid "September"
|
msgid "September"
|
||||||
msgstr "Septiembre"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
||||||
msgid "October"
|
msgid "October"
|
||||||
msgstr "Octubre"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
||||||
msgid "November"
|
msgid "November"
|
||||||
msgstr "Noviembre"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr "Diciembre"
|
msgstr ""
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Your request has been queued on the server and will now be processed. If "
|
#~ "Your request has been queued on the server and will now be processed. If "
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: French\n"
|
"Project-Id-Version: French\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2018-10-28 10:23+0000\n"
|
"PO-Revision-Date: 2018-10-28 10:23+0000\n"
|
||||||
"Last-Translator: Arnaud Vergnet <keplyx@gmail.com>\n"
|
"Last-Translator: Arnaud Vergnet <keplyx@gmail.com>\n"
|
||||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-01-02 08:20+0000\n"
|
"PO-Revision-Date: 2019-01-02 08:20+0000\n"
|
||||||
"Last-Translator: amefad <fame@libero.it>\n"
|
"Last-Translator: amefad <fame@libero.it>\n"
|
||||||
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
|
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: 1\n"
|
"Project-Id-Version: 1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-24 05:00+0000\n"
|
"PO-Revision-Date: 2019-03-13 15:49+0000\n"
|
||||||
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
|
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
|
||||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
"nl/>\n"
|
"nl/>\n"
|
||||||
@@ -16,7 +16,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 3.5.1\n"
|
"X-Generator: Weblate 3.4\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -40,7 +40,7 @@ msgstr "Betaalde bestellingen"
|
|||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
||||||
msgid "Total revenue"
|
msgid "Total revenue"
|
||||||
msgstr "Totaalomzet"
|
msgstr "Volledige omzet"
|
||||||
|
|
||||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:12
|
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:12
|
||||||
msgid "Contacting Stripe …"
|
msgid "Contacting Stripe …"
|
||||||
@@ -226,11 +226,13 @@ msgstr "Aantal"
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Ja"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "None"
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "Nee"
|
msgstr "Geen"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
||||||
msgid "(one more date)"
|
msgid "(one more date)"
|
||||||
@@ -292,12 +294,12 @@ msgstr "plus %(rate)s% %(taxname)s"
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "incl. taxes"
|
msgid "incl. taxes"
|
||||||
msgstr "incl. belasting"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "plus taxes"
|
msgid "plus taxes"
|
||||||
msgstr "excl. belasting"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
@@ -392,100 +394,102 @@ msgid "See variations"
|
|||||||
msgstr "Zie variaties"
|
msgstr "Zie variaties"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Use a different name internally"
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Choose a different event"
|
msgid "Choose a different event"
|
||||||
msgstr "Ander evenement kiezen"
|
msgstr "Gebruik intern een andere naam"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Terug"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Next month"
|
msgid "Next month"
|
||||||
msgstr "Volgende maand"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Previous month"
|
msgid "Previous month"
|
||||||
msgstr "Vorige maand"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
||||||
msgid "Mo"
|
msgid "Mo"
|
||||||
msgstr "Ma"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
||||||
msgid "Tu"
|
msgid "Tu"
|
||||||
msgstr "Di"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
||||||
msgid "We"
|
msgid "We"
|
||||||
msgstr "Wo"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
||||||
msgid "Th"
|
msgid "Th"
|
||||||
msgstr "Do"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
||||||
msgid "Fr"
|
msgid "Fr"
|
||||||
msgstr "Vr"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
||||||
msgid "Sa"
|
msgid "Sa"
|
||||||
msgstr "Za"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
||||||
msgid "Su"
|
msgid "Su"
|
||||||
msgstr "Zo"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
||||||
msgid "January"
|
msgid "January"
|
||||||
msgstr "Januari"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
||||||
msgid "February"
|
msgid "February"
|
||||||
msgstr "Februari"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
||||||
msgid "March"
|
msgid "March"
|
||||||
msgstr "Maart"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
||||||
msgid "April"
|
msgid "April"
|
||||||
msgstr "April"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
||||||
msgid "May"
|
msgid "May"
|
||||||
msgstr "Mei"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
||||||
msgid "June"
|
msgid "June"
|
||||||
msgstr "Juni"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
||||||
msgid "July"
|
msgid "July"
|
||||||
msgstr "Juli"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
||||||
msgid "August"
|
msgid "August"
|
||||||
msgstr "Augustus"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
||||||
msgid "September"
|
msgid "September"
|
||||||
msgstr "September"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
||||||
msgid "October"
|
msgid "October"
|
||||||
msgstr "Oktober"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
||||||
msgid "November"
|
msgid "November"
|
||||||
msgstr "November"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr "December"
|
msgstr ""
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "Your request has been queued on the server and will now be processed. If "
|
#~ "Your request has been queued on the server and will now be processed. If "
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Automatically generated\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-27 01:00+0000\n"
|
"PO-Revision-Date: 2019-03-13 15:49+0000\n"
|
||||||
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
|
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
|
||||||
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
|
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
|
||||||
"pretix-js/nl_Informal/>\n"
|
"pretix-js/nl_Informal/>\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 3.5.1\n"
|
"X-Generator: Weblate 3.4\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -41,7 +41,7 @@ msgstr "Betaalde bestellingen"
|
|||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
||||||
msgid "Total revenue"
|
msgid "Total revenue"
|
||||||
msgstr "Totaalomzet"
|
msgstr "Volledige omzet"
|
||||||
|
|
||||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:12
|
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:12
|
||||||
msgid "Contacting Stripe …"
|
msgid "Contacting Stripe …"
|
||||||
@@ -228,11 +228,13 @@ msgstr "Aantal"
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
#: pretix/static/pretixcontrol/js/ui/question.js:120
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
msgstr "Ja"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
#: pretix/static/pretixcontrol/js/ui/question.js:121
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "None"
|
||||||
msgid "No"
|
msgid "No"
|
||||||
msgstr "Nee"
|
msgstr "Geen"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
#: pretix/static/pretixcontrol/js/ui/subevent.js:108
|
||||||
msgid "(one more date)"
|
msgid "(one more date)"
|
||||||
@@ -294,12 +296,12 @@ msgstr "plus %(rate)s% %(taxname)s"
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "incl. taxes"
|
msgid "incl. taxes"
|
||||||
msgstr "incl. belasting"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "plus taxes"
|
msgid "plus taxes"
|
||||||
msgstr "excl. belasting"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
@@ -394,97 +396,99 @@ msgid "See variations"
|
|||||||
msgstr "Zie variaties"
|
msgstr "Zie variaties"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Use a different name internally"
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Choose a different event"
|
msgid "Choose a different event"
|
||||||
msgstr "Ander evenement kiezen"
|
msgstr "Gebruik intern een andere naam"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Terug"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Next month"
|
msgid "Next month"
|
||||||
msgstr "Volgende maand"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Previous month"
|
msgid "Previous month"
|
||||||
msgstr "Vorige maand"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
#: pretix/static/pretixpresale/js/widget/widget.js:46
|
||||||
msgid "Mo"
|
msgid "Mo"
|
||||||
msgstr "Ma"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
||||||
msgid "Tu"
|
msgid "Tu"
|
||||||
msgstr "Di"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
||||||
msgid "We"
|
msgid "We"
|
||||||
msgstr "Wo"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
||||||
msgid "Th"
|
msgid "Th"
|
||||||
msgstr "Do"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
||||||
msgid "Fr"
|
msgid "Fr"
|
||||||
msgstr "Vr"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
||||||
msgid "Sa"
|
msgid "Sa"
|
||||||
msgstr "Za"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
||||||
msgid "Su"
|
msgid "Su"
|
||||||
msgstr "Zo"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
||||||
msgid "January"
|
msgid "January"
|
||||||
msgstr "Januari"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
||||||
msgid "February"
|
msgid "February"
|
||||||
msgstr "Februari"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
||||||
msgid "March"
|
msgid "March"
|
||||||
msgstr "Maart"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
||||||
msgid "April"
|
msgid "April"
|
||||||
msgstr "April"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
||||||
msgid "May"
|
msgid "May"
|
||||||
msgstr "Mei"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
||||||
msgid "June"
|
msgid "June"
|
||||||
msgstr "Juni"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
||||||
msgid "July"
|
msgid "July"
|
||||||
msgstr "Juli"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
||||||
msgid "August"
|
msgid "August"
|
||||||
msgstr "Augustus"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
||||||
msgid "September"
|
msgid "September"
|
||||||
msgstr "September"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
||||||
msgid "October"
|
msgid "October"
|
||||||
msgstr "Oktober"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
||||||
msgid "November"
|
msgid "November"
|
||||||
msgstr "November"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr "December"
|
msgstr ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-15 11:19+0000\n"
|
"PO-Revision-Date: 2019-03-15 11:19+0000\n"
|
||||||
"Last-Translator: Serge Bazanski <q3k@hackerspace.pl>\n"
|
"Last-Translator: Serge Bazanski <q3k@hackerspace.pl>\n"
|
||||||
"Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Automatically generated\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-19 09:00+0000\n"
|
"PO-Revision-Date: 2019-03-19 09:00+0000\n"
|
||||||
"Last-Translator: Vitor Reis <vitor.reis7@gmail.com>\n"
|
"Last-Translator: Vitor Reis <vitor.reis7@gmail.com>\n"
|
||||||
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
|
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-04-03 13:19+0000\n"
|
"POT-Creation-Date: 2019-03-22 14:50+0000\n"
|
||||||
"PO-Revision-Date: 2019-01-02 08:21+0000\n"
|
"PO-Revision-Date: 2019-01-02 08:21+0000\n"
|
||||||
"Last-Translator: Alexey Zh <write2aracon@gmail.com>\n"
|
"Last-Translator: Alexey Zh <write2aracon@gmail.com>\n"
|
||||||
"Language-Team: Russian <https://translate.pretix.eu/projects/pretix/pretix-"
|
"Language-Team: Russian <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user