Compare commits

..
223 changed files with 95749 additions and 147560 deletions
-8
View File
@@ -60,14 +60,6 @@ http {
deny all; deny all;
return 404; return 404;
} }
location /static/staticfiles.json {
deny all;
return 404;
}
location /static/CACHE/manifest.json {
deny all;
return 404;
}
location /static/ { location /static/ {
alias /pretix/src/pretix/static.dist/; alias /pretix/src/pretix/static.dist/;
access_log off; access_log off;
@@ -248,14 +248,6 @@ The following snippet is an example on how to configure a nginx proxy for pretix
return 404; return 404;
} }
location /static/staticfiles.json {
deny all;
return 404;
}
location /static/CACHE/manifest.json {
deny all;
return 404;
}
location /static/ { location /static/ {
alias /var/pretix/venv/lib/python3.11/site-packages/pretix/static.dist/; alias /var/pretix/venv/lib/python3.11/site-packages/pretix/static.dist/;
access_log off; access_log off;
-7
View File
@@ -97,7 +97,6 @@ lines list of objects The actual invo
├ gross_value money (string) Price including taxes ├ gross_value money (string) Price including taxes
├ tax_value money (string) Tax amount included ├ tax_value money (string) Tax amount included
├ tax_name string Name of used tax rate (e.g. "VAT") ├ tax_name string Name of used tax rate (e.g. "VAT")
├ tax_code string Codified reason for tax rate (or ``null``), see :ref:`rest-taxcodes`.
└ tax_rate decimal (string) Used tax rate └ tax_rate decimal (string) Used tax rate
foreign_currency_display string If the invoice should also show the total and tax foreign_currency_display string If the invoice should also show the total and tax
amount in a different currency, this contains the amount in a different currency, this contains the
@@ -127,10 +126,6 @@ internal_reference string Customer's refe
The ``event`` attribute has been added. The organizer-level endpoint has been added. The ``event`` attribute has been added. The organizer-level endpoint has been added.
.. versionchanged:: 2024.8
The ``tax_code`` attribute has been added.
List of all invoices List of all invoices
-------------------- --------------------
@@ -208,7 +203,6 @@ List of all invoices
"gross_value": "23.00", "gross_value": "23.00",
"tax_value": "0.00", "tax_value": "0.00",
"tax_name": "VAT", "tax_name": "VAT",
"tax_code": "S/standard",
"tax_rate": "0.00" "tax_rate": "0.00"
} }
], ],
@@ -348,7 +342,6 @@ Fetching individual invoices
"gross_value": "23.00", "gross_value": "23.00",
"tax_value": "0.00", "tax_value": "0.00",
"tax_name": "VAT", "tax_name": "VAT",
"tax_code": "S/standard",
"tax_rate": "0.00" "tax_rate": "0.00"
} }
], ],
+2 -16
View File
@@ -84,7 +84,6 @@ fees list of objects List of fees in
├ tax_rate decimal (string) VAT rate applied for this fee ├ tax_rate decimal (string) VAT rate applied for this fee
├ tax_value money (string) VAT included in this fee ├ tax_value money (string) VAT included in this fee
├ tax_rule integer The ID of the used tax rule (or ``null``) ├ tax_rule integer The ID of the used tax rule (or ``null``)
├ tax_code string Codified reason for tax rate (or ``null``), see :ref:`rest-taxcodes`.
└ canceled boolean Whether or not this fee has been canceled. └ canceled boolean Whether or not this fee has been canceled.
downloads list of objects List of ticket download options for order-wise ticket downloads list of objects List of ticket download options for order-wise ticket
downloading. This might be a multi-page PDF or a ZIP downloading. This might be a multi-page PDF or a ZIP
@@ -160,10 +159,6 @@ cancellation_date datetime Time of order c
The ``cancellation_date`` attribute has been added and can also be used as an ordering key. The ``cancellation_date`` attribute has been added and can also be used as an ordering key.
.. versionchanged:: 2025.1
The ``tax_code`` attribute has been added.
.. _order-position-resource: .. _order-position-resource:
Order position resource Order position resource
@@ -200,7 +195,6 @@ voucher_budget_use money (string) Amount of money
are changed *after* the order was created. Can be ``null``. are changed *after* the order was created. Can be ``null``.
tax_rate decimal (string) VAT rate applied for this position tax_rate decimal (string) VAT rate applied for this position
tax_value money (string) VAT included in this position tax_value money (string) VAT included in this position
tax_code string Codified reason for tax rate (or ``null``), see :ref:`rest-taxcodes`.
tax_rule integer The ID of the used tax rule (or ``null``) tax_rule integer The ID of the used tax rule (or ``null``)
secret string Secret code printed on the tickets for validation secret string Secret code printed on the tickets for validation
addon_to integer Internal ID of the position this position is an add-on for (or ``null``) addon_to integer Internal ID of the position this position is an add-on for (or ``null``)
@@ -261,10 +255,6 @@ pdf_data object Data object req
The attribute ``print_logs`` has been added. The attribute ``print_logs`` has been added.
.. versionchanged:: 2025.1
The ``tax_code`` attribute has been added.
.. _order-payment-resource: .. _order-payment-resource:
Order payment resource Order payment resource
@@ -416,7 +406,6 @@ List of all orders
"tax_rate": "0.00", "tax_rate": "0.00",
"tax_value": "0.00", "tax_value": "0.00",
"tax_rule": null, "tax_rule": null,
"tax_code": null,
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", "secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
"addon_to": null, "addon_to": null,
"subevent": null, "subevent": null,
@@ -656,7 +645,6 @@ Fetching individual orders
"tax_rate": "0.00", "tax_rate": "0.00",
"tax_rule": null, "tax_rule": null,
"tax_value": "0.00", "tax_value": "0.00",
"tax_code": null,
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", "secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
"addon_to": null, "addon_to": null,
"subevent": null, "subevent": null,
@@ -855,7 +843,7 @@ Generating new secrets
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/regenerate_secrets/ .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/regenerate_secrets/
Triggers generation of new ``secret`` and ``ẁeb_secret`` attributes for both the order and all order positions. Triggers generation of new ``secret`` attributes for both the order and all order positions.
**Example request**: **Example request**:
@@ -886,7 +874,7 @@ Generating new secrets
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/regenerate_secrets/ .. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/regenerate_secrets/
Triggers generation of a new ``secret`` and ``web_secret`` attribute for a single order position. Triggers generation of a new ``secret`` attribute for a single order position.
**Example request**: **Example request**:
@@ -1625,7 +1613,6 @@ List of all order positions
"tax_rate": "0.00", "tax_rate": "0.00",
"tax_rule": null, "tax_rule": null,
"tax_value": "0.00", "tax_value": "0.00",
"tax_code": null,
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", "secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
"discount": null, "discount": null,
"pseudonymization_id": "MQLJvANO3B", "pseudonymization_id": "MQLJvANO3B",
@@ -1752,7 +1739,6 @@ Fetching individual positions
"tax_rate": "0.00", "tax_rate": "0.00",
"tax_rule": null, "tax_rule": null,
"tax_value": "0.00", "tax_value": "0.00",
"tax_code": null,
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", "secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
"addon_to": null, "addon_to": null,
"subevent": null, "subevent": null,
+1 -112
View File
@@ -249,7 +249,7 @@ Endpoints
"orderposition": null, "orderposition": null,
"cartposition": null, "cartposition": null,
"voucher": null "voucher": null
} },
:param organizer: The ``slug`` field of the organizer to modify :param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify :param event: The ``slug`` field of the event to modify
@@ -260,114 +260,3 @@ Endpoints
:statuscode 401: Authentication failure :statuscode 401: Authentication failure
:statuscode 403: The requested organizer or event does not exist **or** you have no permission to change this resource. :statuscode 403: The requested organizer or event does not exist **or** you have no permission to change this resource.
:statuscode 404: Seat does not exist; or the endpoint without subevent id was used for event with subevents, or vice versa. :statuscode 404: Seat does not exist; or the endpoint without subevent id was used for event with subevents, or vice versa.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/seats/bulk_block/
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/seats/bulk_block/
Set the ``blocked`` attribute to ``true`` for a large number of seats at once.
You can pass either a list of ``id`` values or a list of ``seat_guid`` values.
You can pass up to 10,000 seats in one request.
The endpoint will return an error if you pass a seat ID that does not exist.
However, it will not return an error if one of the passed seats is already blocked or sold.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/seats/bulk_block/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"ids": [12, 45, 56]
}
or
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/seats/bulk_block/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"seat_guids": ["6c0e29e5-05d6-421f-99f3-afd01478ecad", "c2899340-e2e7-4d05-8100-000a4b6d7cf4"]
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param subevent_id: The ``id`` field of the subevent to modify
:statuscode 200: no error
:statuscode 400: The seat could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer or event does not exist **or** you have no permission to change this resource.
:statuscode 404: Seat does not exist; or the endpoint without subevent id was used for event with subevents, or vice versa.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/seats/bulk_unblock/
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/subevents/(id)/seats/bulk_unblock/
Set the ``blocked`` attribute to ``false`` for a large number of seats at once.
You can pass either a list of ``id`` values or a list of ``seat_guid`` values.
You can pass up to 10,000 seats in one request.
The endpoint will return an error if you pass a seat ID that does not exist.
However, it will not return an error if one of the passed seat is already unblocked or is sold.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/seats/bulk_unblock/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"ids": [12, 45, 56]
}
or
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/seats/bulk_unblock/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"seat_guids": ["6c0e29e5-05d6-421f-99f3-afd01478ecad", "c2899340-e2e7-4d05-8100-000a4b6d7cf4"]
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param subevent_id: The ``id`` field of the subevent to modify
:statuscode 200: no error
:statuscode 400: The seat could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer or event does not exist **or** you have no permission to change this resource.
:statuscode 404: Seat does not exist; or the endpoint without subevent id was used for event with subevents, or vice versa.
-47
View File
@@ -1,8 +1,3 @@
.. spelling:word-list::
EN16931
DSFinV-K
.. _rest-taxrules: .. _rest-taxrules:
Tax rules Tax rules
@@ -23,7 +18,6 @@ id integer Internal ID of
name multi-lingual string The tax rules' name name multi-lingual string The tax rules' name
internal_name string An optional name that is only used in the backend internal_name string An optional name that is only used in the backend
rate decimal (string) Tax rate in percent rate decimal (string) Tax rate in percent
code string Codified reason for tax rate (or ``null``), see :ref:`rest-taxcodes`.
price_includes_tax boolean If ``true`` (default), tax is assumed to be included in price_includes_tax boolean If ``true`` (default), tax is assumed to be included in
the specified product price the specified product price
eu_reverse_charge boolean **DEPRECATED**. If ``true``, EU reverse charge rules eu_reverse_charge boolean **DEPRECATED**. If ``true``, EU reverse charge rules
@@ -48,42 +42,6 @@ custom_rules object Dynamic rules s
The ``custom_rules`` attribute has been added. The ``custom_rules`` attribute has been added.
.. versionchanged:: 2023.8
The ``code`` attribute has been added.
.. _rest-taxcodes:
Tax codes
---------
For integration with external systems, such as electronic invoicing or bookkeeping systems, the tax rate itself is often
not sufficient information. For example, there could be many different reasons why a sale has a tax rate of 0 %, but the
external handling of the transaction depends on which reason applies. Therefore, pretix allows to supply a codified
reason that allows us to understand what the specific legal situation is. These tax codes are modeled after a combination
of the code lists from the European standard EN16931 and the German standard DSFinV-K.
The following codes are supported:
- ``S/standard`` -- Standard VAT rate in the merchant country
- ``S/reduced`` -- Reduced VAT rate in the merchant country
- ``S/averaged`` -- Averaged VAT rate in the merchant country (known use case: agricultural businesses in Germany)
- ``AE`` -- Reverse charge
- ``O`` -- Services outside of scope of tax
- ``E`` -- Exempt from tax (no reason given)
- ``E/<reason>`` -- Exempt from tax, where ``<reason>`` is one of the codes listed in the `VATEX code list`_ version 5.0.
- ``Z`` -- Zero-rated goods
- ``G`` -- Free export item, VAT not charged
- ``K`` -- VAT exempt for EEA intra-community supply of goods and services
- ``L`` -- Canary Islands general indirect tax
- ``M`` -- Tax for production, services and importation in Ceuta and Melilla
- ``B`` -- Transferred (VAT), only in Italy
The code set in the ``code`` attribute of the tax rule is used by default. When ``eu_reverse_charge`` is active, the
code is replaced by ``AE`` for reverse charge sales and by ``O`` for non-EU sales. When configuring custom rules, you
should actively set a ``"code"`` key on each rule. Only for ``"action": "reverse"`` we automatically apply the code
``AE``, in all other cases the default ``code`` of the tax rule is selected.
Endpoints Endpoints
--------- ---------
@@ -116,7 +74,6 @@ Endpoints
"id": 1, "id": 1,
"name": {"en": "VAT"}, "name": {"en": "VAT"},
"internal_name": "VAT", "internal_name": "VAT",
"code": "S/standard",
"rate": "19.00", "rate": "19.00",
"price_includes_tax": true, "price_includes_tax": true,
"eu_reverse_charge": false, "eu_reverse_charge": false,
@@ -158,7 +115,6 @@ Endpoints
"id": 1, "id": 1,
"name": {"en": "VAT"}, "name": {"en": "VAT"},
"internal_name": "VAT", "internal_name": "VAT",
"code": "S/standard",
"rate": "19.00", "rate": "19.00",
"price_includes_tax": true, "price_includes_tax": true,
"eu_reverse_charge": false, "eu_reverse_charge": false,
@@ -208,7 +164,6 @@ Endpoints
"id": 1, "id": 1,
"name": {"en": "VAT"}, "name": {"en": "VAT"},
"internal_name": "VAT", "internal_name": "VAT",
"code": "S/standard",
"rate": "19.00", "rate": "19.00",
"price_includes_tax": true, "price_includes_tax": true,
"eu_reverse_charge": false, "eu_reverse_charge": false,
@@ -257,7 +212,6 @@ Endpoints
"id": 1, "id": 1,
"name": {"en": "VAT"}, "name": {"en": "VAT"},
"internal_name": "VAT", "internal_name": "VAT",
"code": "S/standard",
"rate": "20.00", "rate": "20.00",
"price_includes_tax": true, "price_includes_tax": true,
"eu_reverse_charge": false, "eu_reverse_charge": false,
@@ -304,4 +258,3 @@ Endpoints
:statuscode 403: The requested organizer/event/rule does not exist **or** you have no permission to change it **or** this tax rule cannot be deleted since it is currently in use. :statuscode 403: The requested organizer/event/rule does not exist **or** you have no permission to change it **or** this tax rule cannot be deleted since it is currently in use.
.. _here: https://github.com/pretix/pretix/blob/master/src/pretix/static/schema/tax-rules-custom.schema.json .. _here: https://github.com/pretix/pretix/blob/master/src/pretix/static/schema/tax-rules-custom.schema.json
.. _VATEX code list: https://ec.europa.eu/digital-building-blocks/sites/display/DIGITAL/Registry+of+supporting+artefacts+to+implement+EN16931#RegistryofsupportingartefactstoimplementEN16931-Codelists
+5 -5
View File
@@ -32,7 +32,7 @@ dependencies = [
"bleach==6.2.*", "bleach==6.2.*",
"celery==5.4.*", "celery==5.4.*",
"chardet==5.2.*", "chardet==5.2.*",
"cryptography>=44.0.0", "cryptography>=3.4.2",
"css-inline==0.14.*", "css-inline==0.14.*",
"defusedcsv>=1.1.0", "defusedcsv>=1.1.0",
"Django[argon2]==4.2.*,>=4.2.15", "Django[argon2]==4.2.*,>=4.2.15",
@@ -44,7 +44,7 @@ dependencies = [
"django-formtools==2.5.1", "django-formtools==2.5.1",
"django-hierarkey==1.2.*", "django-hierarkey==1.2.*",
"django-hijack==3.7.*", "django-hijack==3.7.*",
"django-i18nfield==1.10.*", "django-i18nfield==1.9.*,>=1.9.4",
"django-libsass==0.9", "django-libsass==0.9",
"django-localflavor==4.0", "django-localflavor==4.0",
"django-markup", "django-markup",
@@ -74,7 +74,7 @@ dependencies = [
"paypal-checkout-serversdk==1.0.*", "paypal-checkout-serversdk==1.0.*",
"PyJWT==2.9.*", "PyJWT==2.9.*",
"phonenumberslite==8.13.*", "phonenumberslite==8.13.*",
"Pillow==11.1.*", "Pillow==11.0.*",
"pretix-plugin-build", "pretix-plugin-build",
"protobuf==5.29.*", "protobuf==5.29.*",
"psycopg2-binary", "psycopg2-binary",
@@ -97,10 +97,10 @@ dependencies = [
"text-unidecode==1.*", "text-unidecode==1.*",
"tlds>=2020041600", "tlds>=2020041600",
"tqdm==4.*", "tqdm==4.*",
"ua-parser==1.0.*", "ua-parser==0.18.*",
"vat_moss_forked==2020.3.20.0.11.0", "vat_moss_forked==2020.3.20.0.11.0",
"vobject==0.9.*", "vobject==0.9.*",
"webauthn==2.4.*", "webauthn==2.2.*",
"zeep==4.3.*" "zeep==4.3.*"
] ]
+1 -1
View File
@@ -103,7 +103,7 @@ class SalesChannelMigrationMixin:
] ]
}) })
if set(data["sales_channels"]) == all_channels: if data["sales_channels"] == all_channels:
data["all_sales_channels"] = True data["all_sales_channels"] = True
data["limit_sales_channels"] = [] data["limit_sales_channels"] = []
else: else:
+6 -43
View File
@@ -35,7 +35,7 @@
import logging import logging
from django.conf import settings from django.conf import settings
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied, ValidationError
from django.db import transaction from django.db import transaction
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
from django.utils.functional import cached_property from django.utils.functional import cached_property
@@ -43,7 +43,6 @@ from django.utils.translation import gettext as _
from django_countries.serializers import CountryFieldMixin from django_countries.serializers import CountryFieldMixin
from pytz import common_timezones from pytz import common_timezones
from rest_framework import serializers from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.fields import ChoiceField, Field from rest_framework.fields import ChoiceField, Field
from rest_framework.relations import SlugRelatedField from rest_framework.relations import SlugRelatedField
@@ -437,8 +436,7 @@ class CloneEventSerializer(EventSerializer):
testmode = validated_data.pop('testmode', None) testmode = validated_data.pop('testmode', None)
has_subevents = validated_data.pop('has_subevents', None) has_subevents = validated_data.pop('has_subevents', None)
tz = validated_data.pop('timezone', None) tz = validated_data.pop('timezone', None)
all_sales_channels = validated_data.pop('all_sales_channels', None) sales_channels = validated_data.pop('sales_channels', None)
limit_sales_channels = validated_data.pop('limit_sales_channels', None)
date_admission = validated_data.pop('date_admission', None) date_admission = validated_data.pop('date_admission', None)
new_event = super().create({**validated_data, 'plugins': None}) new_event = super().create({**validated_data, 'plugins': None})
@@ -451,9 +449,8 @@ class CloneEventSerializer(EventSerializer):
new_event.is_public = is_public new_event.is_public = is_public
if testmode is not None: if testmode is not None:
new_event.testmode = testmode new_event.testmode = testmode
if all_sales_channels is not None or limit_sales_channels is not None: if sales_channels is not None:
new_event.all_sales_channels = all_sales_channels new_event.sales_channels = sales_channels
new_event.limit_sales_channels.set(limit_sales_channels)
if has_subevents is not None: if has_subevents is not None:
new_event.has_subevents = has_subevents new_event.has_subevents = has_subevents
if has_subevents is not None: if has_subevents is not None:
@@ -681,8 +678,8 @@ class TaxRuleSerializer(CountryFieldMixin, I18nAwareModelSerializer):
class Meta: class Meta:
model = TaxRule model = TaxRule
fields = ('id', 'name', 'rate', 'code', 'price_includes_tax', 'eu_reverse_charge', 'home_country', fields = ('id', 'name', 'rate', 'price_includes_tax', 'eu_reverse_charge', 'home_country', 'internal_name',
'internal_name', 'keep_gross_if_rate_changes', 'custom_rules') 'keep_gross_if_rate_changes', 'custom_rules')
class EventSettingsSerializer(SettingsSerializer): class EventSettingsSerializer(SettingsSerializer):
@@ -992,40 +989,6 @@ def prefetch_by_id(items, qs, id_attr, target_attr):
setattr(item, target_attr, result.get(getattr(item, id_attr))) setattr(item, target_attr, result.get(getattr(item, id_attr)))
class SeatBulkBlockInputSerializer(serializers.Serializer):
ids = serializers.ListField(child=serializers.IntegerField(), required=False, allow_empty=True)
seat_guids = serializers.ListField(child=serializers.CharField(), required=False, allow_empty=True)
def to_internal_value(self, data):
data = super().to_internal_value(data)
if data.get("seat_guids") and data.get("ids"):
raise ValidationError("Please pass either seat_guids or ids.")
if data.get("seat_guids"):
seat_ids = data["seat_guids"]
if len(seat_ids) > 10000:
raise ValidationError({"seat_guids": ["Please do not pass over 10000 seats."]})
seats = {s.seat_guid: s for s in self.context["queryset"].filter(seat_guid__in=seat_ids)}
for s in seat_ids:
if s not in seats:
raise ValidationError({"seat_guids": [f"The seat '{s}' does not exist."]})
elif data.get("ids"):
seat_ids = data["ids"]
if len(seat_ids) > 10000:
raise ValidationError({"ids": ["Please do not pass over 10000 seats."]})
seats = self.context["queryset"].in_bulk(seat_ids)
for s in seat_ids:
if s not in seats:
raise ValidationError({"ids": [f"The seat '{s}' does not exist."]})
else:
raise ValidationError("Please pass either seat_guids or ids.")
return {"seats": seats.values()}
class SeatSerializer(I18nAwareModelSerializer): class SeatSerializer(I18nAwareModelSerializer):
orderposition = serializers.IntegerField(source='orderposition_id') orderposition = serializers.IntegerField(source='orderposition_id')
cartposition = serializers.IntegerField(source='cartposition_id') cartposition = serializers.IntegerField(source='cartposition_id')
+50 -8
View File
@@ -19,8 +19,57 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see # You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
from django.conf import settings
from django.core.validators import URLValidator from django.core.validators import URLValidator
from i18nfield.rest_framework import I18nAwareModelSerializer, I18nField from i18nfield.fields import I18nCharField, I18nTextField
from i18nfield.strings import LazyI18nString
from rest_framework.exceptions import ValidationError
from rest_framework.fields import Field
from rest_framework.serializers import ModelSerializer
class I18nField(Field):
def __init__(self, **kwargs):
self.allow_blank = kwargs.pop('allow_blank', False)
self.trim_whitespace = kwargs.pop('trim_whitespace', True)
self.max_length = kwargs.pop('max_length', None)
self.min_length = kwargs.pop('min_length', None)
super().__init__(**kwargs)
def to_representation(self, value):
if hasattr(value, 'data'):
if isinstance(value.data, dict):
return value.data
elif value.data is None:
return None
else:
return {
settings.LANGUAGE_CODE: str(value.data)
}
elif value is None:
return None
else:
return {
settings.LANGUAGE_CODE: str(value)
}
def to_internal_value(self, data):
if isinstance(data, str):
return LazyI18nString(data)
elif isinstance(data, dict):
if any([k not in dict(settings.LANGUAGES) for k in data.keys()]):
raise ValidationError('Invalid languages included.')
return LazyI18nString(data)
else:
raise ValidationError('Invalid data type.')
class I18nAwareModelSerializer(ModelSerializer):
pass
I18nAwareModelSerializer.serializer_field_mapping[I18nCharField] = I18nField
I18nAwareModelSerializer.serializer_field_mapping[I18nTextField] = I18nField
class I18nURLField(I18nField): class I18nURLField(I18nField):
@@ -35,10 +84,3 @@ class I18nURLField(I18nField):
else: else:
URLValidator()(value.data) URLValidator()(value.data)
return value return value
__all__ = [
"I18nAwareModelSerializer", # for backwards compatibility
"I18nField", # for backwards compatibility
"I18nURLField",
]
+5 -7
View File
@@ -512,12 +512,11 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
'company', 'street', 'zipcode', 'city', 'country', 'state', 'discount', 'company', 'street', 'zipcode', 'city', 'country', 'state', 'discount',
'attendee_email', 'voucher', 'tax_rate', 'tax_value', 'secret', 'addon_to', 'subevent', 'checkins', 'attendee_email', 'voucher', 'tax_rate', 'tax_value', 'secret', 'addon_to', 'subevent', 'checkins',
'print_logs', 'downloads', 'answers', 'tax_rule', 'pseudonymization_id', 'pdf_data', 'seat', 'canceled', 'print_logs', 'downloads', 'answers', 'tax_rule', 'pseudonymization_id', 'pdf_data', 'seat', 'canceled',
'print_logs', 'downloads', 'answers', 'tax_rule', 'tax_code', 'pseudonymization_id', 'pdf_data', 'seat', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use')
'canceled', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use')
read_only_fields = ( read_only_fields = (
'id', 'order', 'positionid', 'item', 'variation', 'price', 'voucher', 'tax_rate', 'tax_value', 'secret', 'id', 'order', 'positionid', 'item', 'variation', 'price', 'voucher', 'tax_rate', 'tax_value', 'secret',
'addon_to', 'subevent', 'checkins', 'downloads', 'answers', 'tax_rule', 'tax_code', 'pseudonymization_id', 'addon_to', 'subevent', 'checkins', 'downloads', 'answers', 'tax_rule', 'pseudonymization_id', 'pdf_data',
'pdf_data', 'seat', 'canceled', 'discount', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use' 'seat', 'canceled', 'discount', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use'
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -643,8 +642,7 @@ class OrderPaymentDateField(serializers.DateField):
class OrderFeeSerializer(I18nAwareModelSerializer): class OrderFeeSerializer(I18nAwareModelSerializer):
class Meta: class Meta:
model = OrderFee model = OrderFee
fields = ('id', 'fee_type', 'value', 'description', 'internal_type', 'tax_rate', 'tax_value', 'tax_rule', fields = ('id', 'fee_type', 'value', 'description', 'internal_type', 'tax_rate', 'tax_value', 'tax_rule', 'canceled')
'tax_code', 'canceled')
class PaymentURLField(serializers.URLField): class PaymentURLField(serializers.URLField):
@@ -1678,7 +1676,7 @@ class InlineInvoiceLineSerializer(I18nAwareModelSerializer):
class Meta: class Meta:
model = InvoiceLine model = InvoiceLine
fields = ('position', 'description', 'item', 'variation', 'subevent', 'attendee_name', 'event_date_from', fields = ('position', 'description', 'item', 'variation', 'subevent', 'attendee_name', 'event_date_from',
'event_date_to', 'gross_value', 'tax_value', 'tax_rate', 'tax_code', 'tax_name', 'fee_type', 'event_date_to', 'gross_value', 'tax_value', 'tax_rate', 'tax_name', 'fee_type',
'fee_internal_type', 'event_location') 'fee_internal_type', 'event_location')
+4 -27
View File
@@ -40,7 +40,6 @@ from django.utils.timezone import now
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from rest_framework import serializers, views, viewsets from rest_framework import serializers, views, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ( from rest_framework.exceptions import (
NotFound, PermissionDenied, ValidationError, NotFound, PermissionDenied, ValidationError,
) )
@@ -51,9 +50,8 @@ from pretix.api.auth.permission import EventCRUDPermission
from pretix.api.pagination import TotalOrderingFilter from pretix.api.pagination import TotalOrderingFilter
from pretix.api.serializers.event import ( from pretix.api.serializers.event import (
CloneEventSerializer, DeviceEventSettingsSerializer, EventSerializer, CloneEventSerializer, DeviceEventSettingsSerializer, EventSerializer,
EventSettingsSerializer, ItemMetaPropertiesSerializer, EventSettingsSerializer, ItemMetaPropertiesSerializer, SeatSerializer,
SeatBulkBlockInputSerializer, SeatSerializer, SubEventSerializer, SubEventSerializer, TaxRuleSerializer,
TaxRuleSerializer,
) )
from pretix.api.views import ConditionalListView from pretix.api.views import ConditionalListView
from pretix.base.models import ( from pretix.base.models import (
@@ -239,9 +237,9 @@ class EventViewSet(viewsets.ModelViewSet):
disabled = {m: 'disabled' for m in current_plugins_value if m not in updated_plugins_value} disabled = {m: 'disabled' for m in current_plugins_value if m not in updated_plugins_value}
changed = merge_dicts(enabled, disabled) changed = merge_dicts(enabled, disabled)
for module, operation in changed.items(): for module, action in changed.items():
serializer.instance.log_action( serializer.instance.log_action(
'pretix.event.plugins.' + operation, 'pretix.event.plugins.' + action,
user=self.request.user, user=self.request.user,
auth=self.request.auth, auth=self.request.auth,
data={'plugin': module} data={'plugin': module}
@@ -746,24 +744,3 @@ class SeatViewSet(ConditionalListView, viewsets.ModelViewSet):
auth=self.request.auth, auth=self.request.auth,
data={"seats": [serializer.instance.pk]}, data={"seats": [serializer.instance.pk]},
) )
def bulk_change_blocked(self, blocked):
s = SeatBulkBlockInputSerializer(
data=self.request.data,
context={"event": self.request.event, "queryset": self.get_queryset()},
)
s.is_valid(raise_exception=True)
seats = s.validated_data["seats"]
for seat in seats:
seat.blocked = blocked
Seat.objects.bulk_update(seats, ["blocked"], batch_size=1000)
return Response({})
@action(methods=["POST"], detail=False)
def bulk_block(self, request, *args, **kwargs):
return self.bulk_change_blocked(True)
@action(methods=["POST"], detail=False)
def bulk_unblock(self, request, *args, **kwargs):
return self.bulk_change_blocked(False)
+2 -6
View File
@@ -35,7 +35,6 @@ from django.db.models import (
from django.db.models.functions import Coalesce, Concat from django.db.models.functions import Coalesce, Concat
from django.http import FileResponse, HttpResponse from django.http import FileResponse, HttpResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils import formats
from django.utils.timezone import make_aware, now from django.utils.timezone import make_aware, now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
@@ -68,7 +67,6 @@ from pretix.api.serializers.orderchange import (
OrderPositionInfoPatchSerializer, OrderPositionInfoPatchSerializer,
) )
from pretix.api.views import RichOrderingFilter from pretix.api.views import RichOrderingFilter
from pretix.base.decimal import round_decimal
from pretix.base.i18n import language from pretix.base.i18n import language
from pretix.base.models import ( from pretix.base.models import (
CachedCombinedTicket, CachedTicket, Checkin, Device, EventMetaValue, CachedCombinedTicket, CachedTicket, Checkin, Device, EventMetaValue,
@@ -99,6 +97,7 @@ from pretix.base.services.tickets import generate
from pretix.base.signals import ( from pretix.base.signals import (
order_modified, order_paid, order_placed, register_ticket_outputs, order_modified, order_paid, order_placed, register_ticket_outputs,
) )
from pretix.base.templatetags.money import money_filter
from pretix.control.signals import order_search_filter_q from pretix.control.signals import order_search_filter_q
from pretix.helpers import OF_SELF from pretix.helpers import OF_SELF
@@ -647,8 +646,6 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
order = self.get_object() order = self.get_object()
order.secret = generate_secret() order.secret = generate_secret()
for op in order.all_positions.all(): for op in order.all_positions.all():
op.web_secret = generate_secret()
op.save(update_fields=["web_secret"])
assign_ticket_secret( assign_ticket_secret(
request.event, op, force_invalidate=True, save=True request.event, op, force_invalidate=True, save=True
) )
@@ -1231,10 +1228,9 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
price = get_price(**kwargs) price = get_price(**kwargs)
tr = kwargs.get('tax_rule', kwargs.get('item').tax_rule) tr = kwargs.get('tax_rule', kwargs.get('item').tax_rule)
with language(data.get('locale') or self.request.event.settings.locale, self.request.event.settings.region): with language(data.get('locale') or self.request.event.settings.locale, self.request.event.settings.region):
gross_formatted = formats.localize_input(round_decimal(price.gross, self.request.event.currency))
return Response({ return Response({
'gross': price.gross, 'gross': price.gross,
'gross_formatted': gross_formatted, 'gross_formatted': money_filter(price.gross, self.request.event.currency, hide_currency=True),
'net': price.net, 'net': price.net,
'rate': price.rate, 'rate': price.rate,
'name': str(price.name), 'name': str(price.name),
+2 -6
View File
@@ -35,7 +35,6 @@ from django.utils.translation import get_language, gettext_lazy as _
from pretix.base.models import Event from pretix.base.models import Event
from pretix.base.signals import register_html_mail_renderers from pretix.base.signals import register_html_mail_renderers
from pretix.base.templatetags.rich_text import markdown_compile_email from pretix.base.templatetags.rich_text import markdown_compile_email
from pretix.helpers.format import SafeFormatter, format_map
from pretix.base.services.placeholders import ( # noqa from pretix.base.services.placeholders import ( # noqa
get_available_placeholders, PlaceholderContext get_available_placeholders, PlaceholderContext
@@ -80,7 +79,7 @@ class BaseHTMLMailRenderer:
return self.identifier return self.identifier
def render(self, plain_body: str, plain_signature: str, subject: str, order=None, def render(self, plain_body: str, plain_signature: str, subject: str, order=None,
position=None, context=None) -> str: position=None) -> str:
""" """
This method should generate the HTML part of the email. This method should generate the HTML part of the email.
@@ -89,7 +88,6 @@ class BaseHTMLMailRenderer:
:param subject: The email subject. :param subject: The email subject.
:param order: The order if this email is connected to one, otherwise ``None``. :param order: The order if this email is connected to one, otherwise ``None``.
:param position: The order position if this email is connected to one, otherwise ``None``. :param position: The order position if this email is connected to one, otherwise ``None``.
:param context: Context to use to render placeholders in the plain body
:return: An HTML string :return: An HTML string
""" """
raise NotImplementedError() raise NotImplementedError()
@@ -136,10 +134,8 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
def compile_markdown(self, plaintext): def compile_markdown(self, plaintext):
return markdown_compile_email(plaintext) return markdown_compile_email(plaintext)
def render(self, plain_body: str, plain_signature: str, subject: str, order, position, context) -> str: def render(self, plain_body: str, plain_signature: str, subject: str, order, position) -> str:
body_md = self.compile_markdown(plain_body) body_md = self.compile_markdown(plain_body)
if context:
body_md = format_map(body_md, context=context, mode=SafeFormatter.MODE_RICH_TO_HTML)
htmlctx = { htmlctx = {
'site': settings.PRETIX_INSTANCE_NAME, 'site': settings.PRETIX_INSTANCE_NAME,
'site_url': settings.SITE_URL, 'site_url': settings.SITE_URL,
+4 -4
View File
@@ -100,7 +100,7 @@ class MarkdownTextarea(forms.Textarea):
class I18nMarkdownTextarea(i18nfield.forms.I18nTextarea): class I18nMarkdownTextarea(i18nfield.forms.I18nTextarea):
def format_output(self, rendered_widgets, id_) -> str: def format_output(self, rendered_widgets) -> str:
rendered_widgets = rendered_widgets + [ rendered_widgets = rendered_widgets + [
'<div class="i18n-field-markdown-note">%s</div>' % ( '<div class="i18n-field-markdown-note">%s</div>' % (
_("You can use {markup_name} in this field.").format( _("You can use {markup_name} in this field.").format(
@@ -108,11 +108,11 @@ class I18nMarkdownTextarea(i18nfield.forms.I18nTextarea):
) )
) )
] ]
return super().format_output(rendered_widgets, id_) return super().format_output(rendered_widgets)
class I18nMarkdownTextInput(i18nfield.forms.I18nTextInput): class I18nMarkdownTextInput(i18nfield.forms.I18nTextInput):
def format_output(self, rendered_widgets, id_) -> str: def format_output(self, rendered_widgets) -> str:
rendered_widgets = rendered_widgets + [ rendered_widgets = rendered_widgets + [
'<div class="i18n-field-markdown-note">%s</div>' % ( '<div class="i18n-field-markdown-note">%s</div>' % (
_("You can use {markup_name} in this field.").format( _("You can use {markup_name} in this field.").format(
@@ -120,7 +120,7 @@ class I18nMarkdownTextInput(i18nfield.forms.I18nTextInput):
) )
) )
] ]
return super().format_output(rendered_widgets, id_) return super().format_output(rendered_widgets)
SECRET_REDACTED = '*****' SECRET_REDACTED = '*****'
+7 -23
View File
@@ -1035,18 +1035,6 @@ class BaseInvoiceAddressForm(forms.ModelForm):
'is_business': '' 'is_business': ''
} }
@property
def ask_vat_id(self):
return self.event.settings.invoice_address_vatid
@property
def address_required(self):
return self.event.settings.invoice_address_required
@property
def company_required(self):
return self.event.settings.invoice_address_company_required
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.event = event = kwargs.pop('event') self.event = event = kwargs.pop('event')
self.request = kwargs.pop('request', None) self.request = kwargs.pop('request', None)
@@ -1058,11 +1046,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
kwargs['initial']['country'] = guess_country_from_request(self.request, self.event) kwargs['initial']['country'] = guess_country_from_request(self.request, self.event)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if not event.settings.invoice_address_vatid:
self.fields["company"].widget.attrs["data-display-dependency"] = f'#id_{self.add_prefix("is_business")}_1'
self.fields["vat_id"].widget.attrs["data-display-dependency"] = f'#id_{self.add_prefix("is_business")}_1'
if not self.ask_vat_id:
del self.fields['vat_id'] del self.fields['vat_id']
elif self.validate_vat_id: elif self.validate_vat_id:
self.fields['vat_id'].help_text = '<br/>'.join([ self.fields['vat_id'].help_text = '<br/>'.join([
@@ -1116,13 +1100,13 @@ class BaseInvoiceAddressForm(forms.ModelForm):
self.data = self.data.copy() self.data = self.data.copy()
del self.data[fprefix + 'vat_id'] del self.data[fprefix + 'vat_id']
if not self.address_required or self.all_optional: if not event.settings.invoice_address_required or self.all_optional:
for k, f in self.fields.items(): for k, f in self.fields.items():
f.required = False f.required = False
f.widget.is_required = False f.widget.is_required = False
if 'required' in f.widget.attrs: if 'required' in f.widget.attrs:
del f.widget.attrs['required'] del f.widget.attrs['required']
elif self.company_required and not self.all_optional: elif event.settings.invoice_address_company_required and not self.all_optional:
self.initial['is_business'] = True self.initial['is_business'] = True
self.fields['is_business'].widget = BusinessBooleanRadio(require_business=True) self.fields['is_business'].widget = BusinessBooleanRadio(require_business=True)
@@ -1139,11 +1123,11 @@ class BaseInvoiceAddressForm(forms.ModelForm):
label=_('Name'), label=_('Name'),
initial=self.instance.name_parts, initial=self.instance.name_parts,
) )
if self.address_required and not self.company_required and not self.all_optional: if event.settings.invoice_address_required and not event.settings.invoice_address_company_required and not self.all_optional:
if not event.settings.invoice_name_required: if not event.settings.invoice_name_required:
self.fields['name_parts'].widget.attrs['data-required-if'] = f'#id_{self.add_prefix("is_business")}_0' self.fields['name_parts'].widget.attrs['data-required-if'] = '#id_is_business_0'
self.fields['name_parts'].widget.attrs['data-no-required-attr'] = '1' self.fields['name_parts'].widget.attrs['data-no-required-attr'] = '1'
self.fields['company'].widget.attrs['data-required-if'] = f'#id_{self.add_prefix("is_business")}_1' self.fields['company'].widget.attrs['data-required-if'] = '#id_is_business_1'
if not event.settings.invoice_address_beneficiary: if not event.settings.invoice_address_beneficiary:
del self.fields['beneficiary'] del self.fields['beneficiary']
@@ -1169,7 +1153,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
data['vat_id'] = '' data['vat_id'] = ''
if data.get('is_business') and not ask_for_vat_id(data.get('country')): if data.get('is_business') and not ask_for_vat_id(data.get('country')):
data['vat_id'] = '' data['vat_id'] = ''
if self.address_validation and self.address_required and not self.all_optional: if self.address_validation and self.event.settings.invoice_address_required and not self.all_optional:
if data.get('is_business') and not data.get('company'): if data.get('is_business') and not data.get('company'):
raise ValidationError({"company": _('You need to provide a company name.')}) raise ValidationError({"company": _('You need to provide a company name.')})
if not data.get('is_business') and name_parts_is_empty(data.get('name_parts', {})): if not data.get('is_business') and name_parts_is_empty(data.get('name_parts', {})):
@@ -81,7 +81,7 @@ class Command(BaseCommand):
try: try:
r = receiver(signal=periodic_task, sender=self) r = receiver(signal=periodic_task, sender=self)
except Exception as err: except Exception as err:
if isinstance(err, KeyboardInterrupt): if isinstance(Exception, KeyboardInterrupt):
raise err raise err
if settings.SENTRY_ENABLED: if settings.SENTRY_ENABLED:
from sentry_sdk import capture_exception from sentry_sdk import capture_exception
@@ -1,41 +0,0 @@
# Generated by Django 4.2.8 on 2024-07-02 10:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"pretixbase",
"0273_remove_checkinlist_auto_checkin_sales_channels",
),
]
operations = [
migrations.AddField(
model_name="invoiceline",
name="tax_code",
field=models.CharField(max_length=190, null=True),
),
migrations.AddField(
model_name="orderfee",
name="tax_code",
field=models.CharField(max_length=190, null=True),
),
migrations.AddField(
model_name="orderposition",
name="tax_code",
field=models.CharField(max_length=190, null=True),
),
migrations.AddField(
model_name="taxrule",
name="code",
field=models.CharField(max_length=190, null=True),
),
migrations.AddField(
model_name="transaction",
name="tax_code",
field=models.CharField(max_length=190, null=True),
),
]
+2 -3
View File
@@ -441,7 +441,6 @@ class Price(DecimalColumnMixin, ImportColumn):
position.price = p.gross position.price = p.gross
position.tax_rule = position.item.tax_rule position.tax_rule = position.item.tax_rule
position.tax_rate = p.rate position.tax_rate = p.rate
position.tax_code = p.code
position.tax_value = p.tax position.tax_value = p.tax
@@ -585,7 +584,7 @@ class SeatColumn(ImportColumn):
raise ValidationError(_('Multiple matching seats were found.')) raise ValidationError(_('Multiple matching seats were found.'))
except Seat.DoesNotExist: except Seat.DoesNotExist:
raise ValidationError(_('No matching seat was found.')) raise ValidationError(_('No matching seat was found.'))
if not value.is_available(sales_channel=previous_values.get('sales_channel')) or value in self._cached: if not value.is_available() or value in self._cached:
raise ValidationError( raise ValidationError(
_('The seat you selected has already been taken. Please select a different seat.')) _('The seat you selected has already been taken. Please select a different seat.'))
self._cached.add(value) self._cached.add(value)
@@ -754,11 +753,11 @@ def get_order_import_columns(event):
AttendeeState(event), AttendeeState(event),
Price(event), Price(event),
Secret(event), Secret(event),
Saleschannel(event),
SeatColumn(event), SeatColumn(event),
ValidFrom(event), ValidFrom(event),
ValidUntil(event), ValidUntil(event),
Locale(event), Locale(event),
Saleschannel(event),
CheckinAttentionColumn(event), CheckinAttentionColumn(event),
CheckinTextColumn(event), CheckinTextColumn(event),
Expires(event), Expires(event),
-3
View File
@@ -823,9 +823,6 @@ class Event(EventMixin, LoggedModel):
self.save() self.save()
self.log_action('pretix.object.cloned', data={'source': other.slug, 'source_id': other.pk}) self.log_action('pretix.object.cloned', data={'source': other.slug, 'source_id': other.pk})
if hasattr(other, 'alternative_domain_assignment'):
other.alternative_domain_assignment.domain.event_assignments.create(event=self)
if not self.all_sales_channels: if not self.all_sales_channels:
self.limit_sales_channels.set( self.limit_sales_channels.set(
self.organizer.sales_channels.filter( self.organizer.sales_channels.filter(
-1
View File
@@ -362,7 +362,6 @@ class InvoiceLine(models.Model):
tax_value = models.DecimalField(max_digits=13, decimal_places=2, default=Decimal('0.00')) tax_value = models.DecimalField(max_digits=13, decimal_places=2, default=Decimal('0.00'))
tax_rate = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal('0.00')) tax_rate = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal('0.00'))
tax_name = models.CharField(max_length=190) tax_name = models.CharField(max_length=190)
tax_code = models.CharField(max_length=190, null=True, blank=True)
subevent = models.ForeignKey('SubEvent', null=True, blank=True, on_delete=models.PROTECT) subevent = models.ForeignKey('SubEvent', null=True, blank=True, on_delete=models.PROTECT)
event_date_from = models.DateTimeField(null=True) event_date_from = models.DateTimeField(null=True)
event_date_to = models.DateTimeField(null=True) event_date_to = models.DateTimeField(null=True)
+2 -4
View File
@@ -837,7 +837,7 @@ class Item(LoggedModel):
if not self.tax_rule: if not self.tax_rule:
t = TaxedPrice(gross=price - bundled_sum, net=price - bundled_sum, tax=Decimal('0.00'), t = TaxedPrice(gross=price - bundled_sum, net=price - bundled_sum, tax=Decimal('0.00'),
rate=Decimal('0.00'), name='', code=None) rate=Decimal('0.00'), name='')
else: else:
t = self.tax_rule.tax(price, base_price_is=base_price_is, invoice_address=invoice_address, t = self.tax_rule.tax(price, base_price_is=base_price_is, invoice_address=invoice_address,
override_tax_rate=override_tax_rate, currency=currency or self.event.currency, override_tax_rate=override_tax_rate, currency=currency or self.event.currency,
@@ -845,7 +845,6 @@ class Item(LoggedModel):
if bundled_sum: if bundled_sum:
t.name = "MIXED!" t.name = "MIXED!"
t.code = None
t.gross += bundled_sum t.gross += bundled_sum
t.net += bundled_sum_net t.net += bundled_sum_net
t.tax += bundled_sum_tax t.tax += bundled_sum_tax
@@ -1259,7 +1258,7 @@ class ItemVariation(models.Model):
if not self.item.tax_rule: if not self.item.tax_rule:
t = TaxedPrice(gross=price, net=price, tax=Decimal('0.00'), t = TaxedPrice(gross=price, net=price, tax=Decimal('0.00'),
rate=Decimal('0.00'), name='', code=None) rate=Decimal('0.00'), name='')
else: else:
t = self.item.tax_rule.tax(price, base_price_is=base_price_is, currency=currency, t = self.item.tax_rule.tax(price, base_price_is=base_price_is, currency=currency,
override_tax_rate=override_tax_rate, override_tax_rate=override_tax_rate,
@@ -1281,7 +1280,6 @@ class ItemVariation(models.Model):
t.net += bprice.net - compare_price.net t.net += bprice.net - compare_price.net
t.tax += bprice.tax - compare_price.tax t.tax += bprice.tax - compare_price.tax
t.name = "MIXED!" t.name = "MIXED!"
t.code = None
return t return t
+5 -57
View File
@@ -62,10 +62,9 @@ from django.db.models.signals import post_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.urls import reverse from django.urls import reverse
from django.utils.crypto import get_random_string, salted_hmac from django.utils.crypto import get_random_string, salted_hmac
from django.utils.encoding import escape_uri_path, force_str from django.utils.encoding import escape_uri_path
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.hashable import make_hashable
from django.utils.timezone import get_current_timezone, make_aware, now from django.utils.timezone import get_current_timezone, make_aware, now
from django.utils.translation import gettext_lazy as _, pgettext_lazy from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django_countries.fields import Country from django_countries.fields import Country
@@ -1257,7 +1256,7 @@ class Order(LockModel, LoggedModel):
keys = set(target_transaction_count.keys()) | set(current_transaction_count.keys()) keys = set(target_transaction_count.keys()) | set(current_transaction_count.keys())
create = [] create = []
for k in keys: for k in keys:
positionid, itemid, variationid, subeventid, price, taxrate, taxruleid, taxvalue, feetype, internaltype, taxcode = k positionid, itemid, variationid, subeventid, price, taxrate, taxruleid, taxvalue, feetype, internaltype = k
d = target_transaction_count[k] - current_transaction_count[k] d = target_transaction_count[k] - current_transaction_count[k]
if d: if d:
create.append(Transaction( create.append(Transaction(
@@ -1273,7 +1272,6 @@ class Order(LockModel, LoggedModel):
tax_rate=taxrate, tax_rate=taxrate,
tax_rule_id=taxruleid, tax_rule_id=taxruleid,
tax_value=taxvalue, tax_value=taxvalue,
tax_code=taxcode,
fee_type=feetype, fee_type=feetype,
internal_type=internaltype, internal_type=internaltype,
)) ))
@@ -2277,7 +2275,6 @@ class OrderFee(models.Model):
FEE_TYPE_SERVICE = "service" FEE_TYPE_SERVICE = "service"
FEE_TYPE_CANCELLATION = "cancellation" FEE_TYPE_CANCELLATION = "cancellation"
FEE_TYPE_INSURANCE = "insurance" FEE_TYPE_INSURANCE = "insurance"
FEE_TYPE_LATE = "late"
FEE_TYPE_OTHER = "other" FEE_TYPE_OTHER = "other"
FEE_TYPE_GIFTCARD = "giftcard" FEE_TYPE_GIFTCARD = "giftcard"
FEE_TYPES = ( FEE_TYPES = (
@@ -2286,7 +2283,6 @@ class OrderFee(models.Model):
(FEE_TYPE_SERVICE, _("Service fee")), (FEE_TYPE_SERVICE, _("Service fee")),
(FEE_TYPE_CANCELLATION, _("Cancellation fee")), (FEE_TYPE_CANCELLATION, _("Cancellation fee")),
(FEE_TYPE_INSURANCE, _("Insurance fee")), (FEE_TYPE_INSURANCE, _("Insurance fee")),
(FEE_TYPE_LATE, _("Late fee")),
(FEE_TYPE_OTHER, _("Other fees")), (FEE_TYPE_OTHER, _("Other fees")),
(FEE_TYPE_GIFTCARD, _("Gift card")), (FEE_TYPE_GIFTCARD, _("Gift card")),
) )
@@ -2315,10 +2311,6 @@ class OrderFee(models.Model):
on_delete=models.PROTECT, on_delete=models.PROTECT,
null=True, blank=True null=True, blank=True
) )
tax_code = models.CharField(
max_length=190,
null=True, blank=True,
)
tax_value = models.DecimalField( tax_value = models.DecimalField(
max_digits=13, decimal_places=2, max_digits=13, decimal_places=2,
verbose_name=_('Tax value') verbose_name=_('Tax value')
@@ -2346,16 +2338,6 @@ class OrderFee(models.Model):
self._transaction_key_reset() self._transaction_key_reset()
return super().refresh_from_db(using, fields) return super().refresh_from_db(using, fields)
def get_tax_code_display(self):
from pretix.base.models.tax import get_tax_code_labels
if self.tax_code:
choices_dict = get_tax_code_labels()
return force_str(
choices_dict.get(make_hashable(self.tax_code), self.tax_code), strings_only=True
)
return ""
def _transaction_key_reset(self): def _transaction_key_reset(self):
self.__initial_transaction_key = Transaction.key(self) self.__initial_transaction_key = Transaction.key(self)
self.__initial_canceled = self.canceled self.__initial_canceled = self.canceled
@@ -2386,11 +2368,9 @@ class OrderFee(models.Model):
if self.tax_rule: if self.tax_rule:
tax = self.tax_rule.tax(self.value, base_price_is='gross', invoice_address=ia, force_fixed_gross_price=True) tax = self.tax_rule.tax(self.value, base_price_is='gross', invoice_address=ia, force_fixed_gross_price=True)
self.tax_rate = tax.rate self.tax_rate = tax.rate
self.tax_code = tax.code
self.tax_value = tax.tax self.tax_value = tax.tax
else: else:
self.tax_value = Decimal('0.00') self.tax_value = Decimal('0.00')
self.tax_code = None
self.tax_rate = Decimal('0.00') self.tax_rate = Decimal('0.00')
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@@ -2399,7 +2379,6 @@ class OrderFee(models.Model):
if self.tax_rate is None: if self.tax_rate is None:
self._calculate_tax() self._calculate_tax()
self.order.touch() self.order.touch()
if not self.get_deferred_fields(): if not self.get_deferred_fields():
@@ -2487,10 +2466,6 @@ class OrderPosition(AbstractPosition):
on_delete=models.PROTECT, on_delete=models.PROTECT,
null=True, blank=True null=True, blank=True
) )
tax_code = models.CharField(
max_length=190,
null=True, blank=True,
)
tax_value = models.DecimalField( tax_value = models.DecimalField(
max_digits=13, decimal_places=2, max_digits=13, decimal_places=2,
verbose_name=_('Tax value') verbose_name=_('Tax value')
@@ -2548,16 +2523,6 @@ class OrderPosition(AbstractPosition):
models.UniqueConstraint("organizer", "secret", name="orderposition_organizer_secret_uniq") models.UniqueConstraint("organizer", "secret", name="orderposition_organizer_secret_uniq")
] ]
def get_tax_code_display(self):
from pretix.base.models.tax import get_tax_code_labels
if self.tax_code:
choices_dict = get_tax_code_labels()
return force_str(
choices_dict.get(make_hashable(self.tax_code), self.tax_code), strings_only=True
)
return ""
@cached_property @cached_property
def sort_key(self): def sort_key(self):
return self.addon_to.positionid if self.addon_to else self.positionid, self.addon_to_id or 0, self.positionid return self.addon_to.positionid if self.addon_to else self.positionid, self.addon_to_id or 0, self.positionid
@@ -2730,13 +2695,11 @@ class OrderPosition(AbstractPosition):
if self.tax_rule: if self.tax_rule:
tax = self.tax_rule.tax(self.price, invoice_address=ia, base_price_is='gross', force_fixed_gross_price=True) tax = self.tax_rule.tax(self.price, invoice_address=ia, base_price_is='gross', force_fixed_gross_price=True)
self.tax_rate = tax.rate self.tax_rate = tax.rate
self.tax_code = tax.code
self.tax_value = tax.tax self.tax_value = tax.tax
if tax.gross != self.price: if tax.gross != self.price:
raise ValueError('Invalid tax calculation') raise ValueError('Invalid tax calculation')
else: else:
self.tax_value = Decimal('0.00') self.tax_value = Decimal('0.00')
self.tax_code = None
self.tax_rate = Decimal('0.00') self.tax_rate = Decimal('0.00')
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@@ -3007,10 +2970,6 @@ class Transaction(models.Model):
on_delete=models.PROTECT, on_delete=models.PROTECT,
null=True, blank=True null=True, blank=True
) )
tax_code = models.CharField(
max_length=190,
null=True, blank=True,
)
tax_value = models.DecimalField( tax_value = models.DecimalField(
max_digits=13, decimal_places=2, max_digits=13, decimal_places=2,
verbose_name=_('Tax value') verbose_name=_('Tax value')
@@ -3031,27 +2990,17 @@ class Transaction(models.Model):
raise ValidationError('Should set either item or fee type') raise ValidationError('Should set either item or fee type')
return super().save(*args, **kwargs) return super().save(*args, **kwargs)
def get_tax_code_display(self):
from pretix.base.models.tax import get_tax_code_labels
if self.tax_code:
choices_dict = get_tax_code_labels()
return force_str(
choices_dict.get(make_hashable(self.tax_code), self.tax_code), strings_only=True
)
return ""
@staticmethod @staticmethod
def key(obj): def key(obj):
if isinstance(obj, Transaction): if isinstance(obj, Transaction):
return (obj.positionid, obj.item_id, obj.variation_id, obj.subevent_id, obj.price, obj.tax_rate, return (obj.positionid, obj.item_id, obj.variation_id, obj.subevent_id, obj.price, obj.tax_rate,
obj.tax_rule_id, obj.tax_value, obj.fee_type, obj.internal_type, obj.tax_code) obj.tax_rule_id, obj.tax_value, obj.fee_type, obj.internal_type)
elif isinstance(obj, OrderPosition): elif isinstance(obj, OrderPosition):
return (obj.positionid, obj.item_id, obj.variation_id, obj.subevent_id, obj.price, obj.tax_rate, return (obj.positionid, obj.item_id, obj.variation_id, obj.subevent_id, obj.price, obj.tax_rate,
obj.tax_rule_id, obj.tax_value, None, None, obj.tax_code) obj.tax_rule_id, obj.tax_value, None, None)
elif isinstance(obj, OrderFee): elif isinstance(obj, OrderFee):
return (None, None, None, None, obj.value, obj.tax_rate, return (None, None, None, None, obj.value, obj.tax_rate,
obj.tax_rule_id, obj.tax_value, obj.fee_type, obj.internal_type, obj.tax_code) obj.tax_rule_id, obj.tax_value, obj.fee_type, obj.internal_type)
raise ValueError('invalid state') # noqa raise ValueError('invalid state') # noqa
@property @property
@@ -3215,7 +3164,6 @@ class CartPosition(AbstractPosition):
if line_price.gross != self.line_price_gross or line_price.rate != self.tax_rate: if line_price.gross != self.line_price_gross or line_price.rate != self.tax_rate:
self.line_price_gross = line_price.gross self.line_price_gross = line_price.gross
self.tax_rate = line_price.rate self.tax_rate = line_price.rate
self.tax_code = line_price.code
self.save(update_fields=['line_price_gross', 'tax_rate']) self.save(update_fields=['line_price_gross', 'tax_rate'])
@property @property
+12 -220
View File
@@ -21,7 +21,6 @@
# #
import json import json
from decimal import Decimal from decimal import Decimal
from typing import Optional
import jsonschema import jsonschema
from django.contrib.staticfiles import finders from django.contrib.staticfiles import finders
@@ -31,9 +30,8 @@ from django.db import models
from django.utils.deconstruct import deconstructible from django.utils.deconstruct import deconstructible
from django.utils.formats import localize from django.utils.formats import localize
from django.utils.functional import lazy from django.utils.functional import lazy
from django.utils.hashable import make_hashable
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _, pgettext, pgettext_lazy from django.utils.translation import gettext_lazy as _, pgettext
from i18nfield.fields import I18nCharField from i18nfield.fields import I18nCharField
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
@@ -44,7 +42,7 @@ from pretix.helpers.countries import FastCountryField
class TaxedPrice: class TaxedPrice:
def __init__(self, *, gross: Decimal, net: Decimal, tax: Decimal, rate: Decimal, name: str, code: Optional[str]): def __init__(self, *, gross: Decimal, net: Decimal, tax: Decimal, rate: Decimal, name: str):
if net + tax != gross: if net + tax != gross:
raise ValueError('Net value and tax value need to add to the gross value') raise ValueError('Net value and tax value need to add to the gross value')
self.gross = gross self.gross = gross
@@ -52,7 +50,6 @@ class TaxedPrice:
self.tax = tax self.tax = tax
self.rate = rate self.rate = rate
self.name = name self.name = name
self.code = code
def __repr__(self): def __repr__(self):
return '{} + {}% = {}'.format(localize(self.net), localize(self.rate), localize(self.gross)) return '{} + {}% = {}'.format(localize(self.net), localize(self.rate), localize(self.gross))
@@ -75,7 +72,6 @@ class TaxedPrice:
tax=newgross - newnet, tax=newgross - newnet,
rate=self.rate, rate=self.rate,
name=self.name, name=self.name,
code=self.code,
) )
def __mul__(self, other): def __mul__(self, other):
@@ -89,7 +85,6 @@ class TaxedPrice:
tax=newgross - newnet, tax=newgross - newnet,
rate=self.rate, rate=self.rate,
name=self.name, name=self.name,
code=self.code,
) )
def __eq__(self, other): def __eq__(self, other):
@@ -98,8 +93,7 @@ class TaxedPrice:
self.net == other.net and self.net == other.net and
self.tax == other.tax and self.tax == other.tax and
self.rate == other.rate and self.rate == other.rate and
self.name == other.name and self.name == other.name
self.code == other.code
) )
@@ -108,8 +102,7 @@ TAXED_ZERO = TaxedPrice(
net=Decimal('0.00'), net=Decimal('0.00'),
tax=Decimal('0.00'), tax=Decimal('0.00'),
rate=Decimal('0.00'), rate=Decimal('0.00'),
name='', name=''
code=None,
) )
EU_COUNTRIES = { EU_COUNTRIES = {
@@ -132,152 +125,6 @@ VAT_ID_COUNTRIES = EU_COUNTRIES | {'CH', 'NO'}
format_html_lazy = lazy(format_html, str) format_html_lazy = lazy(format_html, str)
TAX_CODE_LISTS = (
# Sources:
# https://ec.europa.eu/digital-building-blocks/sites/display/DIGITAL/Registry+of+supporting+artefacts+to+implement+EN16931#RegistryofsupportingartefactstoimplementEN16931-Codelists#RegistryofsupportingartefactstoimplementEN16931-Codelists
# https://docs.peppol.eu/poacc/billing/3.0/codelist/vatex/
# https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/
# https://www.bzst.de/DE/Unternehmen/Aussenpruefungen/DigitaleSchnittstelleFinV/digitaleschnittstellefinv_node.html#js-toc-entry2
#
# !! When changed, also update tax-rules-custom.schema.json and doc/api/resources/taxrules.rst !!
(
_("Standard rates"),
(
# Standard rate in any country, such as 19% in Germany or 20% in Austria
# DSFinV-K mapping: 1
("S/standard", pgettext_lazy("tax_code", "Standard rate")),
# Reduced rate in any country, such as 7% in Germany or both 10% and 13% in Austria
# DSFinV-K mapping: 2
("S/reduced", pgettext_lazy("tax_code", "Reduced rate")),
# Averaged rate, for example Germany § 24 (1) Nr. 3 UStG "für die übrigen Umsätze" in agricultural and silvicultural businesses
# DSFinV-K mapping: 3
("S/averaged", pgettext_lazy("tax_code", "Averaged rate (other revenue in a agricultural and silvicultural business)")),
# We ignore the German special case of the actual silvicultural products as they won't be sold through pretix (DSFinV-K mapping: 4)
)
),
(
_("Reverse charge"),
(
("AE", pgettext_lazy("tax_code", "Reverse charge")),
)
),
(
_("Tax free"),
(
# DSFinV-K mapping: 5
("O", pgettext_lazy("tax_code", "Services outside of scope of tax")),
# DSFinV-K mapping: 6
("E", pgettext_lazy("tax_code", "Exempt from tax (no reason given)")),
# DSFinV-K mapping: 6
("Z", pgettext_lazy("tax_code", "Zero-rated goods")),
# DSFinV-K mapping: 5
("G", pgettext_lazy("tax_code", "Free export item, VAT not charged")),
# DSFinV-K mapping: 6?
("K", pgettext_lazy("tax_code", "VAT exempt for EEA intra-community supply of goods and services")),
)
),
(
_("Special cases"),
(
("L", pgettext_lazy("tax_code", "Canary Islands general indirect tax")),
("M", pgettext_lazy("tax_code", "Tax for production, services and importation in Ceuta and Melilla")),
("B", pgettext_lazy("tax_code", "Transferred (VAT), only in Italy")),
)
),
(
_("Exempt with specific reason"),
(
("E/VATEX-EU-79-C",
pgettext_lazy("tax_code", "Exempt based on article 79, point c of Council Directive 2006/112/EC")),
*[
(
f"E/VATEX-EU-132-1{letter.upper()}",
lazy(
lambda let: pgettext(
"tax_code",
"Exempt based on article {article}, section {section} ({letter}) of Council "
"Directive 2006/112/EC"
).format(article="132", section="1", letter=let),
str
)(letter)
) for letter in ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q")
],
*[
(
f"E/VATEX-EU-143-1{letter.upper()}",
lazy(
lambda let: pgettext(
"tax_code",
"Exempt based on article {article}, section {section} ({letter}) of Council "
"Directive 2006/112/EC"
).format(article="143", section="1", letter=let),
str
)(letter)
) for letter in ("a", "b", "c", "d", "e", "f", "fa", "g", "h", "i", "j", "k", "l")
],
*[
(
f"E/VATEX-EU-148-{letter.upper()}",
lazy(
lambda let: pgettext(
"tax_code",
"Exempt based on article {article}, section ({letter}) of Council "
"Directive 2006/112/EC"
).format(article="148", letter=let),
str
)(letter)
) for letter in ("a", "b", "c", "d", "e", "f", "g")
],
*[
(
f"E/VATEX-EU-151-1{letter.upper()}",
lazy(
lambda let: pgettext(
"tax_code",
"Exempt based on article {article}, section {section} ({letter}) of Council "
"Directive 2006/112/EC"
).format(article="151", section="1", letter=let),
str
)(letter)
) for letter in ("a", "aa", "b", "c", "d", "e")
],
("E/VATEX-EU-309",
pgettext_lazy("tax_code", "Exempt based on article 309 of Council Directive 2006/112/EC")),
("E/VATEX-EU-D",
pgettext_lazy("tax_code", "Intra-Community acquisition from second hand means of transport")),
("E/VATEX-EU-F",
pgettext_lazy("tax_code", "Intra-Community acquisition of second hand goods")),
("E/VATEX-EU-I",
pgettext_lazy("tax_code", "Intra-Community acquisition of works of art")),
("E/VATEX-EU-J",
pgettext_lazy("tax_code", "Intra-Community acquisition of collectors items and antiques")),
("E/VATEX-FR-FRANCHISE",
pgettext_lazy("tax_code", "France domestic VAT franchise in base")),
("E/VATEX-FR-CNWVAT",
pgettext_lazy("tax_code", "France domestic Credit Notes without VAT, due to supplier forfeit of VAT for discount")),
)
),
)
def get_tax_code_labels():
flat = []
for choice, value in TAX_CODE_LISTS:
if isinstance(value, (list, tuple)):
flat.extend(value)
else:
flat.append((choice, value))
return dict(make_hashable(flat))
def is_eu_country(cc): def is_eu_country(cc):
cc = str(cc) cc = str(cc)
return cc in EU_COUNTRIES return cc in EU_COUNTRIES
@@ -326,14 +173,6 @@ class TaxRule(LoggedModel):
help_text=_('Should be short, e.g. "VAT"'), help_text=_('Should be short, e.g. "VAT"'),
max_length=190, max_length=190,
) )
code = models.CharField(
verbose_name=_('Tax code'),
help_text=_('If you help us understand what this tax rules legally is, we can use this information for '
'eInvoices, exporting to accounting system, etc.'),
null=True, blank=True,
max_length=190,
choices=TAX_CODE_LISTS,
)
rate = models.DecimalField( rate = models.DecimalField(
max_digits=10, max_digits=10,
decimal_places=2, decimal_places=2,
@@ -411,16 +250,6 @@ class TaxRule(LoggedModel):
if self.eu_reverse_charge and not self.home_country: if self.eu_reverse_charge and not self.home_country:
raise ValidationError(_('You need to set your home country to use the reverse charge feature.')) raise ValidationError(_('You need to set your home country to use the reverse charge feature.'))
if self.rate != Decimal("0.00") and self.code and (self.code.split("/")[0] in ("O", "E", "Z", "G", "K", "AE")):
raise ValidationError({
"code": _("A combination of this tax code with a non-zero tax rate does not make sense.")
})
if self.rate == Decimal("0.00") and self.code and (self.code.split("/")[0] in ("S", "L", "M", "B")):
raise ValidationError({
"code": _("A combination of this tax code with a zero tax rate does not make sense.")
})
def __str__(self): def __str__(self):
if self.price_includes_tax: if self.price_includes_tax:
s = _('incl. {rate}% {name}').format(rate=self.rate, name=self.name) s = _('incl. {rate}% {name}').format(rate=self.rate, name=self.name)
@@ -447,9 +276,8 @@ class TaxRule(LoggedModel):
return Decimal(rule.get('rate')) return Decimal(rule.get('rate'))
return Decimal(self.rate) return Decimal(self.rate)
def tax(self, base_price, base_price_is='auto', currency=None, override_tax_rate=None, override_tax_code=None, def tax(self, base_price, base_price_is='auto', currency=None, override_tax_rate=None, invoice_address=None,
invoice_address=None, subtract_from_gross=Decimal('0.00'), gross_price_is_tax_rate: Decimal = None, subtract_from_gross=Decimal('0.00'), gross_price_is_tax_rate: Decimal = None, force_fixed_gross_price=False):
force_fixed_gross_price=False):
from .event import Event from .event import Event
try: try:
currency = currency or self.event.currency currency = currency or self.event.currency
@@ -457,13 +285,6 @@ class TaxRule(LoggedModel):
pass pass
rate = Decimal(self.rate) rate = Decimal(self.rate)
code = self.code
if override_tax_code is not None:
code = override_tax_code
elif invoice_address:
code = self.tax_code_for(invoice_address)
if override_tax_rate is not None: if override_tax_rate is not None:
rate = override_tax_rate rate = override_tax_rate
elif invoice_address: elif invoice_address:
@@ -496,8 +317,11 @@ class TaxRule(LoggedModel):
if rate == Decimal('0.00'): if rate == Decimal('0.00'):
gross = _limit_subtract(base_price, subtract_from_gross) gross = _limit_subtract(base_price, subtract_from_gross)
return TaxedPrice( return TaxedPrice(
net=gross, gross=gross, tax=Decimal('0.00'), net=gross,
rate=rate, name=self.name, code=code, gross=gross,
tax=Decimal('0.00'),
rate=rate,
name=self.name,
) )
if base_price_is == 'auto': if base_price_is == 'auto':
@@ -522,7 +346,7 @@ class TaxRule(LoggedModel):
return TaxedPrice( return TaxedPrice(
net=net, gross=gross, tax=gross - net, net=net, gross=gross, tax=gross - net,
rate=rate, name=self.name, code=code, rate=rate, name=self.name
) )
@property @property
@@ -603,38 +427,6 @@ class TaxRule(LoggedModel):
return True return True
return False return False
def tax_code_for(self, invoice_address):
if self._custom_rules:
rule = self.get_matching_rule(invoice_address)
if rule.get("code"):
return rule["code"]
if rule.get("action", "vat") == "reverse":
return "AE"
return self.code
if not self.eu_reverse_charge:
# No reverse charge rules? Always apply VAT!
return self.code
if not invoice_address or not invoice_address.country:
# No country specified? Always apply VAT!
return self.code
if not is_eu_country(invoice_address.country):
# Non-EU country? "Non-taxable" since not in scope
return "O"
if invoice_address.country == self.home_country:
# Within same EU country? Always apply VAT!
return self.code
if invoice_address.is_business and invoice_address.vat_id and invoice_address.vat_id_validated:
# Reverse charge case
return "AE"
# Consumer in different EU country / invalid VAT
return self.code
def _tax_applicable(self, invoice_address): def _tax_applicable(self, invoice_address):
if self._custom_rules: if self._custom_rules:
rule = self.get_matching_rule(invoice_address) rule = self.get_matching_rule(invoice_address)
+33 -34
View File
@@ -1419,51 +1419,50 @@ class GiftCardPayment(BasePaymentProvider):
def payment_refund_supported(self, payment: OrderPayment) -> bool: def payment_refund_supported(self, payment: OrderPayment) -> bool:
return True return True
def _add_giftcard_to_cart(self, cs, gc):
from pretix.base.services.cart import add_payment_to_cart_session
if gc.currency != self.event.currency:
raise ValidationError(_("This gift card does not support this currency."))
if gc.testmode and not self.event.testmode:
raise ValidationError(_("This gift card can only be used in test mode."))
if not gc.testmode and self.event.testmode:
raise ValidationError(_("Only test gift cards can be used in test mode."))
if gc.expires and gc.expires < time_machine_now():
raise ValidationError(_("This gift card is no longer valid."))
if gc.value <= Decimal("0.00"):
raise ValidationError(_("All credit on this gift card has been used."))
for p in cs.get('payments', []):
if p['provider'] == self.identifier and p['info_data']['gift_card'] == gc.pk:
raise ValidationError(_("This gift card is already used for your payment."))
add_payment_to_cart_session(
cs,
self,
max_value=gc.value,
info_data={
'gift_card': gc.pk,
'gift_card_secret': gc.secret,
}
)
def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str, None]: def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str, None]:
from pretix.base.services.cart import add_payment_to_cart
for p in get_cart(request): for p in get_cart(request):
if p.item.issue_giftcard: if p.item.issue_giftcard:
messages.error(request, _("You cannot pay with gift cards when buying a gift card.")) messages.error(request, _("You cannot pay with gift cards when buying a gift card."))
return return
cs = cart_session(request)
try: try:
gc = self.event.organizer.accepted_gift_cards.get( gc = self.event.organizer.accepted_gift_cards.get(
secret=request.POST.get("giftcard").strip() secret=request.POST.get("giftcard").strip()
) )
cs = cart_session(request) if gc.currency != self.event.currency:
try: messages.error(request, _("This gift card does not support this currency."))
self._add_giftcard_to_cart(cs, gc)
return True
except ValidationError as e:
messages.error(request, str(e.message))
return return
if gc.testmode and not self.event.testmode:
messages.error(request, _("This gift card can only be used in test mode."))
return
if not gc.testmode and self.event.testmode:
messages.error(request, _("Only test gift cards can be used in test mode."))
return
if gc.expires and gc.expires < time_machine_now():
messages.error(request, _("This gift card is no longer valid."))
return
if gc.value <= Decimal("0.00"):
messages.error(request, _("All credit on this gift card has been used."))
return
for p in cs.get('payments', []):
if p['provider'] == self.identifier and p['info_data']['gift_card'] == gc.pk:
messages.error(request, _("This gift card is already used for your payment."))
return
add_payment_to_cart(
request,
self,
max_value=gc.value,
info_data={
'gift_card': gc.pk,
'gift_card_secret': gc.secret,
}
)
return True
except GiftCard.DoesNotExist: except GiftCard.DoesNotExist:
if self.event.vouchers.filter(code__iexact=request.POST.get("giftcard")).exists(): if self.event.vouchers.filter(code__iexact=request.POST.get("giftcard")).exists():
messages.warning(request, _("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below " messages.warning(request, _("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below "
+10 -24
View File
@@ -1426,28 +1426,6 @@ class CartManager:
raise CartError(err) raise CartError(err)
def add_payment_to_cart_session(cart_session, provider, min_value: Decimal=None, max_value: Decimal=None, info_data: dict=None):
"""
:param cart_session: The current cart session.
:param provider: The instance of your payment provider.
:param min_value: The minimum value this payment instrument supports, or ``None`` for unlimited.
:param max_value: The maximum value this payment instrument supports, or ``None`` for unlimited. Highly discouraged
to use for payment providers which charge a payment fee, as this can be very user-unfriendly if
users need a second payment method just for the payment fee of the first method.
:param info_data: A dictionary of information that will be passed through to the ``OrderPayment.info_data`` attribute.
:return:
"""
cart_session.setdefault('payments', [])
cart_session['payments'].append({
'id': str(uuid.uuid4()),
'provider': provider.identifier,
'multi_use_supported': provider.multi_use_supported,
'min_value': str(min_value) if min_value is not None else None,
'max_value': str(max_value) if max_value is not None else None,
'info_data': info_data or {},
})
def add_payment_to_cart(request, provider, min_value: Decimal=None, max_value: Decimal=None, info_data: dict=None): def add_payment_to_cart(request, provider, min_value: Decimal=None, max_value: Decimal=None, info_data: dict=None):
""" """
:param request: The current HTTP request context. :param request: The current HTTP request context.
@@ -1462,7 +1440,16 @@ def add_payment_to_cart(request, provider, min_value: Decimal=None, max_value: D
from pretix.presale.views.cart import cart_session from pretix.presale.views.cart import cart_session
cs = cart_session(request) cs = cart_session(request)
add_payment_to_cart_session(cs, provider, min_value, max_value, info_data) cs.setdefault('payments', [])
cs['payments'].append({
'id': str(uuid.uuid4()),
'provider': provider.identifier,
'multi_use_supported': provider.multi_use_supported,
'min_value': str(min_value) if min_value is not None else None,
'max_value': str(max_value) if max_value is not None else None,
'info_data': info_data or {},
})
def get_fees(event, request, total, invoice_address, payments, positions): def get_fees(event, request, total, invoice_address, payments, positions):
@@ -1513,7 +1500,6 @@ def get_fees(event, request, total, invoice_address, payments, positions):
value=payment_fee, value=payment_fee,
tax_rate=payment_fee_tax.rate, tax_rate=payment_fee_tax.rate,
tax_value=payment_fee_tax.tax, tax_value=payment_fee_tax.tax,
tax_code=payment_fee_tax.code,
tax_rule=payment_fee_tax_rule tax_rule=payment_fee_tax_rule
)) ))
+3 -6
View File
@@ -271,9 +271,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
event_date_from=p.subevent.date_from if invoice.event.has_subevents else invoice.event.date_from, event_date_from=p.subevent.date_from if invoice.event.has_subevents else invoice.event.date_from,
event_date_to=p.subevent.date_to if invoice.event.has_subevents else invoice.event.date_to, event_date_to=p.subevent.date_to if invoice.event.has_subevents else invoice.event.date_to,
event_location=location if invoice.event.settings.invoice_event_location else None, event_location=location if invoice.event.settings.invoice_event_location else None,
tax_rate=p.tax_rate, tax_rate=p.tax_rate, tax_name=p.tax_rule.name if p.tax_rule else ''
tax_code=p.tax_code,
tax_name=p.tax_rule.name if p.tax_rule else ''
) )
if p.tax_rule and p.tax_rule.is_reverse_charge(ia) and p.price and not p.tax_value: if p.tax_rule and p.tax_rule.is_reverse_charge(ia) and p.price and not p.tax_value:
@@ -307,7 +305,6 @@ def build_invoice(invoice: Invoice) -> Invoice:
), ),
tax_value=fee.tax_value, tax_value=fee.tax_value,
tax_rate=fee.tax_rate, tax_rate=fee.tax_rate,
tax_code=fee.tax_code,
tax_name=fee.tax_rule.name if fee.tax_rule else '', tax_name=fee.tax_rule.name if fee.tax_rule else '',
fee_type=fee.fee_type, fee_type=fee.fee_type,
fee_internal_type=fee.internal_type or None, fee_internal_type=fee.internal_type or None,
@@ -494,13 +491,13 @@ def build_preview_invoice_pdf(event):
InvoiceLine.objects.create( InvoiceLine.objects.create(
invoice=invoice, description=_("Sample product {}").format(i + 1), invoice=invoice, description=_("Sample product {}").format(i + 1),
gross_value=tax.gross, tax_value=tax.tax, gross_value=tax.gross, tax_value=tax.tax,
tax_rate=tax.rate, tax_name=tax.name, tax_code=tax.code, tax_rate=tax.rate, tax_name=tax.name
) )
else: else:
for i in range(5): for i in range(5):
InvoiceLine.objects.create( InvoiceLine.objects.create(
invoice=invoice, description=_("Sample product A"), invoice=invoice, description=_("Sample product A"),
gross_value=100, tax_value=0, tax_rate=0, tax_code=None, gross_value=100, tax_value=0, tax_rate=0
) )
return event.invoice_renderer.generate(invoice) return event.invoice_renderer.generate(invoice)
+2 -10
View File
@@ -76,7 +76,7 @@ from pretix.base.services.tasks import TransactionAwareTask
from pretix.base.services.tickets import get_tickets_for_order from pretix.base.services.tickets import get_tickets_for_order
from pretix.base.signals import email_filter, global_email_filter from pretix.base.signals import email_filter, global_email_filter
from pretix.celery_app import app from pretix.celery_app import app
from pretix.helpers.format import SafeFormatter, format_map from pretix.helpers.format import format_map
from pretix.helpers.hierarkey import clean_filename from pretix.helpers.hierarkey import clean_filename
from pretix.multidomain.urlreverse import build_absolute_uri from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.presale.ical import get_private_icals from pretix.presale.ical import get_private_icals
@@ -311,13 +311,7 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
try: try:
if plain_text_only: if plain_text_only:
body_html = None body_html = None
elif 'context' in inspect.signature(renderer.render).parameters:
body_html = renderer.render(content_plain, signature, raw_subject, order, position, context)
elif 'position' in inspect.signature(renderer.render).parameters: elif 'position' in inspect.signature(renderer.render).parameters:
# Backwards compatibility
warnings.warn('Email renderer called without context argument because context argument is not '
'supported.',
DeprecationWarning)
body_html = renderer.render(content_plain, signature, raw_subject, order, position) body_html = renderer.render(content_plain, signature, raw_subject, order, position)
else: else:
# Backwards compatibility # Backwards compatibility
@@ -329,8 +323,6 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
logger.exception('Could not render HTML body') logger.exception('Could not render HTML body')
body_html = None body_html = None
body_plain = format_map(body_plain, context, mode=SafeFormatter.MODE_RICH_TO_PLAIN)
send_task = mail_send_task.si( send_task = mail_send_task.si(
to=[email] if isinstance(email, str) else list(email), to=[email] if isinstance(email, str) else list(email),
cc=cc, cc=cc,
@@ -663,7 +655,7 @@ def render_mail(template, context):
if isinstance(template, LazyI18nString): if isinstance(template, LazyI18nString):
body = str(template) body = str(template)
if context: if context:
body = format_map(body, context, mode=SafeFormatter.MODE_IGNORE_RICH) body = format_map(body, context)
else: else:
tpl = get_template(template) tpl = get_template(template)
body = tpl.render(context) body = tpl.render(context)
+4 -4
View File
@@ -118,7 +118,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user,
c.assign(record.get(c.identifier), order, position, order._address) c.assign(record.get(c.identifier), order, position, order._address)
if position.seat is not None: if position.seat is not None:
lock_seats.append((order.sales_channel, position.seat)) lock_seats.append(position.seat)
except (ValidationError, ImportError) as e: except (ValidationError, ImportError) as e:
raise DataImportError( raise DataImportError(
_('Invalid data in row {row}: {message}').format(row=i, message=str(e)) _('Invalid data in row {row}: {message}').format(row=i, message=str(e))
@@ -128,9 +128,9 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user,
with transaction.atomic(): with transaction.atomic():
# We don't support vouchers, quotas, or memberships here, so we only need to lock if seats are in use # We don't support vouchers, quotas, or memberships here, so we only need to lock if seats are in use
if lock_seats: if lock_seats:
lock_objects([s for c, s in lock_seats], shared_lock_objects=[event]) lock_objects(lock_seats, shared_lock_objects=[event])
for c, s in lock_seats: for s in lock_seats:
if not s.is_available(sales_channel=c): if not s.is_available():
raise DataImportError(_('The seat you selected has already been taken. Please select a different seat.')) raise DataImportError(_('The seat you selected has already been taken. Please select a different seat.'))
save_transactions = [] save_transactions = []
+4 -9
View File
@@ -1721,17 +1721,16 @@ class OrderChangeManager:
try: try:
new_rate = tax_rule.tax_rate_for(ia) new_rate = tax_rule.tax_rate_for(ia)
new_code = tax_rule.tax_code_for(ia)
except TaxRule.SaleNotAllowed: except TaxRule.SaleNotAllowed:
raise OrderError(error_messages['tax_rule_country_blocked']) raise OrderError(error_messages['tax_rule_country_blocked'])
# We use override_tax_rate to make sure .tax() doesn't get clever and re-adjusts the pricing itself # We use override_tax_rate to make sure .tax() doesn't get clever and re-adjusts the pricing itself
if new_rate != pos.tax_rate or new_code != pos.tax_code: if new_rate != pos.tax_rate:
if keep == 'net': if keep == 'net':
new_tax = tax_rule.tax(pos.price - pos.tax_value, base_price_is='net', currency=self.event.currency, new_tax = tax_rule.tax(pos.price - pos.tax_value, base_price_is='net', currency=self.event.currency,
override_tax_rate=new_rate, override_tax_code=new_code) override_tax_rate=new_rate)
else: else:
new_tax = tax_rule.tax(pos.price, base_price_is='gross', currency=self.event.currency, new_tax = tax_rule.tax(pos.price, base_price_is='gross', currency=self.event.currency,
override_tax_rate=new_rate, override_tax_code=new_code) override_tax_rate=new_rate)
self._totaldiff += new_tax.gross - pos.price self._totaldiff += new_tax.gross - pos.price
self._operations.append(self.PriceOperation(pos, new_tax, new_tax.gross - pos.price)) self._operations.append(self.PriceOperation(pos, new_tax, new_tax.gross - pos.price))
self._invoice_dirty = True self._invoice_dirty = True
@@ -2305,7 +2304,6 @@ class OrderChangeManager:
op.position.price = op.price.gross op.position.price = op.price.gross
op.position.tax_rate = op.price.rate op.position.tax_rate = op.price.rate
op.position.tax_value = op.price.tax op.position.tax_value = op.price.tax
op.position.tax_code = op.price.code
op.position.save() op.position.save()
elif isinstance(op, self.TaxRuleOperation): elif isinstance(op, self.TaxRuleOperation):
if isinstance(op.position, OrderPosition): if isinstance(op.position, OrderPosition):
@@ -2402,7 +2400,7 @@ class OrderChangeManager:
elif isinstance(op, self.AddOperation): elif isinstance(op, self.AddOperation):
pos = OrderPosition.objects.create( pos = OrderPosition.objects.create(
item=op.item, variation=op.variation, addon_to=op.addon_to, item=op.item, variation=op.variation, addon_to=op.addon_to,
price=op.price.gross, order=self.order, tax_rate=op.price.rate, tax_code=op.price.code, price=op.price.gross, order=self.order, tax_rate=op.price.rate,
tax_value=op.price.tax, tax_rule=op.item.tax_rule, tax_value=op.price.tax, tax_rule=op.item.tax_rule,
positionid=nextposid, subevent=op.subevent, seat=op.seat, positionid=nextposid, subevent=op.subevent, seat=op.seat,
used_membership=op.membership, valid_from=op.valid_from, valid_until=op.valid_until, used_membership=op.membership, valid_from=op.valid_from, valid_until=op.valid_until,
@@ -2425,8 +2423,6 @@ class OrderChangeManager:
elif isinstance(op, self.SplitOperation): elif isinstance(op, self.SplitOperation):
split_positions.append(op.position) split_positions.append(op.position)
elif isinstance(op, self.RegenerateSecretOperation): elif isinstance(op, self.RegenerateSecretOperation):
op.position.web_secret = generate_secret()
op.position.save(update_fields=["web_secret"])
assign_ticket_secret( assign_ticket_secret(
event=self.event, position=op.position, force_invalidate=True, save=True event=self.event, position=op.position, force_invalidate=True, save=True
) )
@@ -2533,7 +2529,6 @@ class OrderChangeManager:
'new_order': split_order.code, 'new_order': split_order.code,
}) })
op.order = split_order op.order = split_order
op.web_secret = generate_secret()
assign_ticket_secret( assign_ticket_secret(
self.event, position=op, force_invalidate=True, self.event, position=op, force_invalidate=True,
) )
+4 -162
View File
@@ -26,7 +26,6 @@ from decimal import Decimal
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.html import escape
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -40,8 +39,7 @@ from pretix.base.settings import PERSON_NAME_SCHEMES, get_name_parts_localized
from pretix.base.signals import ( from pretix.base.signals import (
register_mail_placeholders, register_text_placeholders, register_mail_placeholders, register_text_placeholders,
) )
from pretix.base.templatetags.rich_text import markdown_compile_email from pretix.helpers.format import SafeFormatter
from pretix.helpers.format import PlainHtmlAlternativeString, SafeFormatter
logger = logging.getLogger('pretix.base.services.placeholders') logger = logging.getLogger('pretix.base.services.placeholders')
@@ -109,91 +107,6 @@ class SimpleFunctionalTextPlaceholder(BaseTextPlaceholder):
return self._sample return self._sample
class BaseRichTextPlaceholder(BaseTextPlaceholder):
"""
This is the base class for all placeholders which can render either to plain text
or to a rich HTML element.
"""
def __init__(self, identifier, args):
self._identifier = identifier
self._args = args
@property
def identifier(self):
return self._identifier
@property
def required_context(self):
return self._args
@property
def is_block(self):
return False
def render(self, context):
return PlainHtmlAlternativeString(
self.render_plain(**{k: context[k] for k in self._args}),
self.render_html(**{k: context[k] for k in self._args}),
self.is_block,
)
def render_html(self, **kwargs):
"""
HTML rendering of the placeholder. Should return "safe" HTML, i.e. everything needs to be
escaped.
"""
raise NotImplementedError
def render_plain(self, **kwargs):
"""
Plain text rendering of the placeholder.
"""
raise NotImplementedError
def render_sample(self, event):
return PlainHtmlAlternativeString(
self.render_sample_plain(event=event),
self.render_sample_html(event=event),
self.is_block,
)
def render_sample_html(self, event):
raise NotImplementedError
def render_sample_plain(self, event):
raise NotImplementedError
class SimpleButtonPlaceholder(BaseRichTextPlaceholder):
def __init__(self, identifier, args, url_func, text_func, sample_url_func, sample_text_func):
super().__init__(identifier, args)
self._url_func = url_func
self._text_func = text_func
self._sample_url_func = sample_url_func
self._sample_text_func = sample_text_func
def render_html(self, **context):
text = self._text_func(**{k: context[k] for k in self._args})
url = self._url_func(**{k: context[k] for k in self._args})
return f'<a href="{url}" class="button">{escape(text)}</a>'
def render_plain(self, **context):
text = self._text_func(**{k: context[k] for k in self._args})
url = self._url_func(**{k: context[k] for k in self._args})
return f'{text}: {url}'
def render_sample_html(self, event):
text = self._sample_text_func(event)
url = self._sample_url_func(event)
return f'<a href="{url}" class="button">{escape(text)}</a>'
def render_sample_plain(self, event):
text = self._sample_text_func(event)
url = self._sample_url_func(event)
return f'{text}: {url}'
class PlaceholderContext(SafeFormatter): class PlaceholderContext(SafeFormatter):
""" """
Holds the contextual arguments and corresponding list of available placeholders for formatting Holds the contextual arguments and corresponding list of available placeholders for formatting
@@ -371,27 +284,6 @@ def base_placeholders(sender, **kwargs):
} }
), ),
), ),
SimpleButtonPlaceholder(
'url_button', ['order', 'event'],
url_func=lambda order, event: build_absolute_uri(
event,
'presale:event.order.open', kwargs={
'order': order.code,
'secret': order.secret,
'hash': order.email_confirm_secret()
}
),
text_func=lambda order, event: _("View order details"),
sample_url_func=lambda event: build_absolute_uri(
event,
'presale:event.order.open', kwargs={
'order': 'F8VVL',
'secret': '6zzjnumtsx136ddy',
'hash': '98kusd8ofsj8dnkd'
}
),
sample_text_func=lambda event: _("View order details"),
),
SimpleFunctionalTextPlaceholder( SimpleFunctionalTextPlaceholder(
'url_info_change', ['order', 'event'], lambda order, event: build_absolute_uri( 'url_info_change', ['order', 'event'], lambda order, event: build_absolute_uri(
event, event,
@@ -456,27 +348,6 @@ def base_placeholders(sender, **kwargs):
} }
), ),
), ),
SimpleButtonPlaceholder(
'url_button', ['event', 'position'],
url_func=lambda event, position: build_absolute_uri(
event,
'presale:event.order.position', kwargs={
'order': position.order.code,
'secret': position.web_secret,
'position': position.positionid
}
),
text_func=lambda event, position: _("View registration details"),
sample_url_func=lambda event: build_absolute_uri(
event,
'presale:event.order.position', kwargs={
'order': 'F8VVL',
'secret': '6zzjnumtsx136ddy',
'position': '123'
}
),
sample_text_func=lambda event: _("View registration details"),
),
SimpleFunctionalTextPlaceholder( SimpleFunctionalTextPlaceholder(
'url_info_change', ['position', 'event'], lambda position, event: build_absolute_uri( 'url_info_change', ['position', 'event'], lambda position, event: build_absolute_uri(
event, event,
@@ -732,8 +603,8 @@ def base_placeholders(sender, **kwargs):
class FormPlaceholderMixin: class FormPlaceholderMixin:
def _set_field_placeholders(self, fn, base_parameters, rich=False): def _set_field_placeholders(self, fn, base_parameters):
placeholders = get_available_placeholders(self.event, base_parameters, rich=rich) placeholders = get_available_placeholders(self.event, base_parameters)
ht = format_placeholders_help_text(placeholders, self.event) ht = format_placeholders_help_text(placeholders, self.event)
if self.fields[fn].help_text: if self.fields[fn].help_text:
self.fields[fn].help_text += ' ' + str(ht) self.fields[fn].help_text += ' ' + str(ht)
@@ -744,7 +615,7 @@ class FormPlaceholderMixin:
) )
def get_available_placeholders(event, base_parameters, rich=False): def get_available_placeholders(event, base_parameters):
if 'order' in base_parameters: if 'order' in base_parameters:
base_parameters.append('invoice_address') base_parameters.append('invoice_address')
base_parameters.append('position_or_address') base_parameters.append('position_or_address')
@@ -753,35 +624,6 @@ def get_available_placeholders(event, base_parameters, rich=False):
if not isinstance(val, (list, tuple)): if not isinstance(val, (list, tuple)):
val = [val] val = [val]
for v in val: for v in val:
if isinstance(v, BaseRichTextPlaceholder) and not rich:
continue
if all(rp in base_parameters for rp in v.required_context): if all(rp in base_parameters for rp in v.required_context):
params[v.identifier] = v params[v.identifier] = v
return params return params
def get_sample_context(event, context_parameters, rich=True):
context_dict = {}
lbl = _('This value will be replaced based on dynamic parameters.')
for k, v in get_available_placeholders(event, context_parameters, rich=rich).items():
sample = v.render_sample(event)
if isinstance(sample, PlainHtmlAlternativeString):
context_dict[k] = PlainHtmlAlternativeString(
sample.plain,
'<{el} class="placeholder placeholder-html" title="{title}">{html}</{el}>'.format(
el='div' if sample.is_block else 'span',
title=lbl,
html=sample.html,
)
)
elif str(sample).strip().startswith('* ') or str(sample).startswith(' '):
context_dict[k] = '<div class="placeholder" title="{}">{}</div>'.format(
lbl,
markdown_compile_email(str(sample))
)
else:
context_dict[k] = '<span class="placeholder" title="{}">{}</span>'.format(
lbl,
escape(sample)
)
return context_dict
+2 -6
View File
@@ -91,11 +91,9 @@ def get_price(item: Item, variation: ItemVariation = None,
if custom_price_is_net: if custom_price_is_net:
price = tax_rule.tax(max(custom_price, price.net), base_price_is='net', override_tax_rate=price.rate, price = tax_rule.tax(max(custom_price, price.net), base_price_is='net', override_tax_rate=price.rate,
override_tax_code=price.code,
invoice_address=invoice_address, subtract_from_gross=bundled_sum) invoice_address=invoice_address, subtract_from_gross=bundled_sum)
else: else:
price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross', override_tax_rate=price.rate, price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross', override_tax_rate=price.rate,
override_tax_code=price.code,
invoice_address=invoice_address, subtract_from_gross=bundled_sum) invoice_address=invoice_address, subtract_from_gross=bundled_sum)
else: else:
price = tax_rule.tax(price, invoice_address=invoice_address, subtract_from_gross=bundled_sum) price = tax_rule.tax(price, invoice_address=invoice_address, subtract_from_gross=bundled_sum)
@@ -148,12 +146,10 @@ def get_line_price(price_after_voucher: Decimal, custom_price_input: Decimal, cu
if custom_price_input_is_net: if custom_price_input_is_net:
price = tax_rule.tax(max(custom_price_input, price.net), base_price_is='net', override_tax_rate=price.rate, price = tax_rule.tax(max(custom_price_input, price.net), base_price_is='net', override_tax_rate=price.rate,
override_tax_code=price.code, invoice_address=invoice_address, invoice_address=invoice_address, subtract_from_gross=bundled_sum)
subtract_from_gross=bundled_sum)
else: else:
price = tax_rule.tax(max(custom_price_input, price.gross), base_price_is='gross', override_tax_rate=price.rate, price = tax_rule.tax(max(custom_price_input, price.gross), base_price_is='gross', override_tax_rate=price.rate,
override_tax_code=price.code, invoice_address=invoice_address, invoice_address=invoice_address, subtract_from_gross=bundled_sum)
subtract_from_gross=bundled_sum)
else: else:
price = tax_rule.tax(price_after_voucher, invoice_address=invoice_address, subtract_from_gross=bundled_sum, price = tax_rule.tax(price_after_voucher, invoice_address=invoice_address, subtract_from_gross=bundled_sum,
base_price_is='gross' if is_bundled else 'auto') base_price_is='gross' if is_bundled else 'auto')
+2 -3
View File
@@ -21,7 +21,6 @@
# #
import logging import logging
import os import os
from decimal import Decimal
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.utils.timezone import now from django.utils.timezone import now
@@ -98,9 +97,9 @@ def preview(event: int, provider: str):
event = Event.objects.get(id=event) event = Event.objects.get(id=event)
with rolledback_transaction(), language(event.settings.locale, event.settings.region): with rolledback_transaction(), language(event.settings.locale, event.settings.region):
item = event.items.create(name=_("Sample product"), default_price=Decimal('42.23'), item = event.items.create(name=_("Sample product"), default_price=42.23,
description=_("Sample product description")) description=_("Sample product description"))
item2 = event.items.create(name=_("Sample workshop"), default_price=Decimal('23.40')) item2 = event.items.create(name=_("Sample workshop"), default_price=23.40)
from pretix.base.models import Order from pretix.base.models import Order
order = event.orders.create(status=Order.STATUS_PENDING, datetime=now(), order = event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
+1 -2
View File
@@ -56,7 +56,6 @@ from django.utils.translation import (
from django_countries.fields import Country from django_countries.fields import Country
from hierarkey.models import GlobalSettingsBase, Hierarkey from hierarkey.models import GlobalSettingsBase, Hierarkey
from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput
from i18nfield.rest_framework import I18nField
from i18nfield.strings import LazyI18nString from i18nfield.strings import LazyI18nString
from phonenumbers import PhoneNumber, parse from phonenumbers import PhoneNumber, parse
from rest_framework import serializers from rest_framework import serializers
@@ -64,7 +63,7 @@ from rest_framework import serializers
from pretix.api.serializers.fields import ( from pretix.api.serializers.fields import (
ListMultipleChoiceField, UploadedFileField, ListMultipleChoiceField, UploadedFileField,
) )
from pretix.api.serializers.i18n import I18nURLField from pretix.api.serializers.i18n import I18nField, I18nURLField
from pretix.base.forms import I18nMarkdownTextarea, I18nURLFormField from pretix.base.forms import I18nMarkdownTextarea, I18nURLFormField
from pretix.base.models.tax import VAT_ID_COUNTRIES, TaxRule from pretix.base.models.tax import VAT_ID_COUNTRIES, TaxRule
from pretix.base.reldate import ( from pretix.base.reldate import (
@@ -131,9 +131,6 @@
text-align: left; text-align: left;
padding: 0; padding: 0;
} }
.content table td.align-right {
text-align: right;
}
a.button { a.button {
display: inline-block; display: inline-block;
@@ -181,9 +178,6 @@
pre, pre code { pre, pre code {
white-space: pre-line; white-space: pre-line;
} }
.text-right, .content table td.text-right {
text-align: right;
}
{% if rtl %} {% if rtl %}
body { body {
@@ -192,9 +186,6 @@
.content { .content {
text-align: right; text-align: right;
} }
.text-right, .content table td.text-right {
text-align: left;
}
{% endif %} {% endif %}
{% block addcss %}{% endblock %} {% block addcss %}{% endblock %}
+4 -4
View File
@@ -52,12 +52,12 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
# would make the numbers incorrect. If this branch executes, it's likely a bug in # would make the numbers incorrect. If this branch executes, it's likely a bug in
# pretix, but we won't show wrong numbers! # pretix, but we won't show wrong numbers!
if hide_currency: if hide_currency:
return floatformat(value, "2g") return floatformat(value, 2)
else: else:
return '{} {}'.format(arg, floatformat(value, "2g")) return '{} {}'.format(arg, floatformat(value, 2))
if hide_currency: if hide_currency:
return floatformat(value, f"{places}g") return floatformat(value, places)
locale_parts = translation.get_language().split("-", 1) locale_parts = translation.get_language().split("-", 1)
locale = locale_parts[0] locale = locale_parts[0]
@@ -70,7 +70,7 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
try: try:
return format_currency(value, arg, locale=locale) return format_currency(value, arg, locale=locale)
except: except:
return '{} {}'.format(arg, floatformat(value, f"{places}g")) return '{} {}'.format(arg, floatformat(value, places))
@register.filter("money_numberfield") @register.filter("money_numberfield")
@@ -305,7 +305,6 @@ def markdown_compile_email(source, allowed_tags=ALLOWED_TAGS, allowed_attributes
source, source,
extensions=[ extensions=[
'markdown.extensions.sane_lists', 'markdown.extensions.sane_lists',
'markdown.extensions.tables',
EmailNl2BrExtension(), EmailNl2BrExtension(),
LinkifyAndCleanExtension( LinkifyAndCleanExtension(
linker, linker,
+41 -104
View File
@@ -35,7 +35,7 @@
# License for the specific language governing permissions and limitations under the License. # License for the specific language governing permissions and limitations under the License.
from decimal import Decimal from decimal import Decimal
from urllib.parse import urlencode from urllib.parse import urlencode, urlparse
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
import pycountry import pycountry
@@ -63,7 +63,6 @@ from pretix.base.forms import (
) )
from pretix.base.models import Event, Organizer, TaxRule, Team from pretix.base.models import Event, Organizer, TaxRule, Team
from pretix.base.models.event import EventFooterLink, EventMetaValue, SubEvent from pretix.base.models.event import EventFooterLink, EventMetaValue, SubEvent
from pretix.base.models.tax import TAX_CODE_LISTS
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
from pretix.base.services.placeholders import FormPlaceholderMixin from pretix.base.services.placeholders import FormPlaceholderMixin
from pretix.base.settings import ( from pretix.base.settings import (
@@ -77,10 +76,8 @@ from pretix.control.forms import (
) )
from pretix.control.forms.widgets import Select2 from pretix.control.forms.widgets import Select2
from pretix.helpers.countries import CachedCountries from pretix.helpers.countries import CachedCountries
from pretix.multidomain.models import AlternativeDomainAssignment, KnownDomain from pretix.multidomain.models import KnownDomain
from pretix.multidomain.urlreverse import ( from pretix.multidomain.urlreverse import build_absolute_uri
build_absolute_uri, get_organizer_domain,
)
from pretix.plugins.banktransfer.payment import BankTransfer from pretix.plugins.banktransfer.payment import BankTransfer
from pretix.presale.style import get_fonts from pretix.presale.style import get_fonts
@@ -366,9 +363,14 @@ class EventUpdateForm(I18nModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.change_slug = kwargs.pop('change_slug', False) self.change_slug = kwargs.pop('change_slug', False)
self.domain = kwargs.pop('domain', False)
kwargs.setdefault('initial', {}) kwargs.setdefault('initial', {})
self.instance = kwargs['instance'] self.instance = kwargs['instance']
if self.domain and self.instance:
initial_domain = self.instance.domains.first()
if initial_domain:
kwargs['initial'].setdefault('domain', initial_domain.domainname)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if not self.change_slug: if not self.change_slug:
@@ -377,54 +379,48 @@ class EventUpdateForm(I18nModelForm):
self.fields['location'].widget.attrs['placeholder'] = _( self.fields['location'].widget.attrs['placeholder'] = _(
'Sample Conference Center\nHeidelberg, Germany' 'Sample Conference Center\nHeidelberg, Germany'
) )
if self.domain:
try:
self.fields['domain'] = forms.CharField( self.fields['domain'] = forms.CharField(
max_length=255, max_length=255,
label=_('Domain'), label=_('Custom domain'),
initial=self.instance.domain.domainname,
required=False,
disabled=True,
help_text=_('You can configure this in your organizer settings.')
)
except KnownDomain.DoesNotExist:
domain = get_organizer_domain(self.instance.organizer)
try:
current_domain_assignment = self.instance.alternative_domain_assignment
except AlternativeDomainAssignment.DoesNotExist:
current_domain_assignment = None
self.fields['domain'] = forms.ChoiceField(
label=_('Domain'),
help_text=_('You can add more domains in your organizer account.'),
choices=[('', _('Same as organizer account') + (f" ({domain})" if domain else ""))] + [
(d.domainname, d.domainname) for d in self.instance.organizer.domains.filter(mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
],
initial=current_domain_assignment.domain_id if current_domain_assignment else "",
required=False, required=False,
help_text=_('You need to configure the custom domain in the webserver beforehand.')
) )
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all() self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all()
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={ self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
'data-inverse-dependency': '<[name$=all_sales_channels]', 'data-inverse-dependency': '<[name$=all_sales_channels]',
}, choices=self.fields['limit_sales_channels'].widget.choices) }, choices=self.fields['limit_sales_channels'].widget.choices)
def clean_domain(self):
d = self.cleaned_data['domain']
if d:
if d == urlparse(settings.SITE_URL).hostname:
raise ValidationError(
_('You cannot choose the base domain of this installation.')
)
if KnownDomain.objects.filter(domainname=d).exclude(event=self.instance.pk).exists():
raise ValidationError(
_('This domain is already in use for a different event or organizer.')
)
return d
def save(self, commit=True): def save(self, commit=True):
instance = super().save(commit) instance = super().save(commit)
try: if self.domain:
current_domain_assignment = instance.alternative_domain_assignment current_domain = instance.domains.first()
except AlternativeDomainAssignment.DoesNotExist: if self.cleaned_data['domain']:
current_domain_assignment = None if current_domain and current_domain.domainname != self.cleaned_data['domain']:
if self.cleaned_data['domain'] and not hasattr(instance, 'domain'): current_domain.delete()
domain = self.instance.organizer.domains.get(mode=KnownDomain.MODE_ORG_ALT_DOMAIN, domainname=self.cleaned_data["domain"]) KnownDomain.objects.create(
AlternativeDomainAssignment.objects.update_or_create( organizer=instance.organizer, event=instance, domainname=self.cleaned_data['domain']
event=instance, )
defaults={ elif not current_domain:
"domain": domain, KnownDomain.objects.create(
} organizer=instance.organizer, event=instance, domainname=self.cleaned_data['domain']
) )
instance.cache.clear() elif current_domain:
elif current_domain_assignment: current_domain.delete()
current_domain_assignment.delete()
instance.cache.clear() instance.cache.clear()
return instance return instance
@@ -1386,7 +1382,7 @@ class MailSettingsForm(FormPlaceholderMixin, SettingsForm):
self.event.meta_values_cached = self.event.meta_values.select_related('property').all() self.event.meta_values_cached = self.event.meta_values.select_related('property').all()
for k, v in self.base_context.items(): for k, v in self.base_context.items():
self._set_field_placeholders(k, v, rich=k.startswith('mail_text_')) self._set_field_placeholders(k, v)
for k, v in list(self.fields.items()): for k, v in list(self.fields.items()):
if k.endswith('_attendee') and not event.settings.attendee_emails_asked: if k.endswith('_attendee') and not event.settings.attendee_emails_asked:
@@ -1505,11 +1501,6 @@ class TaxRuleLineForm(I18nForm):
('require_approval', _('Order requires approval')), ('require_approval', _('Order requires approval')),
], ],
) )
code = forms.ChoiceField(
label=_("Tax code"),
choices=[("", _("Default tax code")), *TAX_CODE_LISTS],
required=False,
)
rate = forms.DecimalField( rate = forms.DecimalField(
label=_('Deviating tax rate'), label=_('Deviating tax rate'),
max_digits=10, decimal_places=2, max_digits=10, decimal_places=2,
@@ -1524,43 +1515,6 @@ class TaxRuleLineForm(I18nForm):
}) })
) )
def __init__(self, *args, **kwargs):
self.parent_form = kwargs.pop("parent_form")
super().__init__(*args, **kwargs)
def clean(self):
d = super().clean()
parent_code = self.parent_form.cleaned_data.get("code")
parent_rate = self.parent_form.cleaned_data.get("rate")
code = d.get("code") or parent_code
rate = d.get("rate")
if rate is None:
rate = parent_rate
if d.get("action") in ("reverse", "no", "block") and d.get("rate"):
raise ValidationError(_("A combination of this calculation mode with a non-zero tax rate does not make sense."))
if d.get("action") == "reverse" and d.get("code") and code != "AE":
# Reverse charge but code is not reverse charge -- this is the one case we ignore if the "default code"
# is used because it is the one scenario we can auto-fix
raise ValidationError(_("This combination of calculation mode and tax code does not make sense."))
if d.get("action") == "no" and code and code.split("/")[0] in ("S", "AE", "L", "M", "B"):
# No VAT but code indicates VAT
raise ValidationError(_("This combination of calculation mode and tax code does not make sense."))
if d.get("action") == "vat" and code and rate != Decimal("0.00") and code.split("/")[0] in ("O", "E", "Z", "G", "K", "AE"):
# VAT, but code indicates exempt
raise ValidationError(_("A combination of this tax code with a non-zero tax rate does not make sense."))
if d.get("action") == "vat" and code and rate == Decimal("0.00") and code.split("/")[0] in ("S", "L", "M", "B"):
# no VAT, but code indicates non-exempt
raise ValidationError(_("A combination of this tax code with a zero tax rate does not make sense."))
return d
class I18nBaseFormSet(I18nFormSetMixin, forms.BaseFormSet): class I18nBaseFormSet(I18nFormSetMixin, forms.BaseFormSet):
# compatibility shim for django-i18nfield library # compatibility shim for django-i18nfield library
@@ -1572,16 +1526,8 @@ class I18nBaseFormSet(I18nFormSetMixin, forms.BaseFormSet):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
class BaseTaxRuleLineFormSet(I18nBaseFormSet):
def __init__(self, *args, **kwargs):
self.parent_form = kwargs.pop('parent_form')
super().__init__(*args, **kwargs)
self.form_kwargs['parent_form'] = self.parent_form
TaxRuleLineFormSet = formset_factory( TaxRuleLineFormSet = formset_factory(
TaxRuleLineForm, formset=BaseTaxRuleLineFormSet, TaxRuleLineForm, formset=I18nBaseFormSet,
can_order=True, can_delete=True, extra=0 can_order=True, can_delete=True, extra=0
) )
@@ -1589,16 +1535,7 @@ TaxRuleLineFormSet = formset_factory(
class TaxRuleForm(I18nModelForm): class TaxRuleForm(I18nModelForm):
class Meta: class Meta:
model = TaxRule model = TaxRule
fields = [ fields = ['name', 'rate', 'price_includes_tax', 'eu_reverse_charge', 'home_country', 'internal_name', 'keep_gross_if_rate_changes']
'name',
'rate',
'price_includes_tax',
'code',
'eu_reverse_charge',
'home_country',
'internal_name',
'keep_gross_if_rate_changes'
]
class WidgetCodeForm(forms.Form): class WidgetCodeForm(forms.Form):
+1 -3
View File
@@ -490,9 +490,7 @@ class OrderPositionChangeForm(forms.Form):
) )
operation_secret = forms.BooleanField( operation_secret = forms.BooleanField(
required=False, required=False,
label=_('Generate a new secret'), label=_('Generate a new secret')
help_text=_('This affects both the ticket secret (often used as a QR code) as well as the link used to '
'individually access the ticket.')
) )
operation_cancel = forms.BooleanField( operation_cancel = forms.BooleanField(
required=False, required=False,
+42 -87
View File
@@ -133,108 +133,63 @@ class OrganizerDeleteForm(forms.Form):
class OrganizerUpdateForm(OrganizerForm): class OrganizerUpdateForm(OrganizerForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.domain = kwargs.pop('domain', False)
self.change_slug = kwargs.pop('change_slug', False) self.change_slug = kwargs.pop('change_slug', False)
kwargs.setdefault('initial', {}) kwargs.setdefault('initial', {})
self.instance = kwargs['instance'] self.instance = kwargs['instance']
if self.domain and self.instance:
initial_domain = self.instance.domains.filter(event__isnull=True).first()
if initial_domain:
kwargs['initial'].setdefault('domain', initial_domain.domainname)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if not self.change_slug: if not self.change_slug:
self.fields['slug'].widget.attrs['readonly'] = 'readonly' self.fields['slug'].widget.attrs['readonly'] = 'readonly'
if self.domain:
self.fields['domain'] = forms.CharField(
max_length=255,
label=_('Custom domain'),
required=False,
help_text=_('You need to configure the custom domain in the webserver beforehand.')
)
def clean_domain(self):
d = self.cleaned_data['domain']
if d:
if d == urlparse(settings.SITE_URL).hostname:
raise ValidationError(
_('You cannot choose the base domain of this installation.')
)
if KnownDomain.objects.filter(domainname=d).exclude(organizer=self.instance.pk,
event__isnull=True).exists():
raise ValidationError(
_('This domain is already in use for a different event or organizer.')
)
return d
def clean_slug(self): def clean_slug(self):
if self.change_slug: if self.change_slug:
return self.cleaned_data['slug'] return self.cleaned_data['slug']
return self.instance.slug return self.instance.slug
def save(self, commit=True):
instance = super().save(commit)
class KnownDomainForm(forms.ModelForm): if self.domain:
class Meta: current_domain = instance.domains.filter(event__isnull=True).first()
model = KnownDomain if self.cleaned_data['domain']:
fields = ["domainname", "mode", "event"] if current_domain and current_domain.domainname != self.cleaned_data['domain']:
field_classes = { current_domain.delete()
"event": SafeModelChoiceField, KnownDomain.objects.create(organizer=instance, domainname=self.cleaned_data['domain'])
} elif not current_domain:
KnownDomain.objects.create(organizer=instance, domainname=self.cleaned_data['domain'])
elif current_domain:
current_domain.delete()
instance.cache.clear()
for ev in instance.events.all():
ev.cache.clear()
def __init__(self, *args, **kwargs): return instance
self.organizer = kwargs.pop('organizer')
super().__init__(*args, **kwargs)
self.fields["event"].queryset = self.organizer.events.all()
if self.instance and self.instance.pk:
self.fields["domainname"].widget.attrs['readonly'] = 'readonly'
def clean_domainname(self):
if self.instance and self.instance.pk:
return self.instance.domainname
d = self.cleaned_data['domainname']
if d:
if d == urlparse(settings.SITE_URL).hostname:
raise ValidationError(
_('You cannot choose the base domain of this installation.')
)
if KnownDomain.objects.filter(domainname=d).exclude(organizer=self.instance.organizer).exists():
raise ValidationError(
_('This domain is already in use for a different event or organizer.')
)
return d
def clean(self):
d = super().clean()
if d["mode"] == KnownDomain.MODE_ORG_DOMAIN and d["event"]:
raise ValidationError(
_("Do not choose an event for this mode.")
)
if d["mode"] == KnownDomain.MODE_ORG_ALT_DOMAIN and d["event"]:
raise ValidationError(
_("Do not choose an event for this mode. You can assign events to this domain in event settings.")
)
if d["mode"] == KnownDomain.MODE_EVENT_DOMAIN and not d["event"]:
raise ValidationError(
_("You need to choose an event.")
)
return d
class BaseKnownDomainFormSet(forms.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
self.organizer = kwargs.pop('organizer')
super().__init__(*args, **kwargs)
def _construct_form(self, i, **kwargs):
kwargs['organizer'] = self.organizer
return super()._construct_form(i, **kwargs)
@property
def empty_form(self):
form = self.form(
auto_id=self.auto_id,
prefix=self.add_prefix('__prefix__'),
empty_permitted=True,
use_required_attribute=False,
organizer=self.organizer,
)
self.add_fields(form, None)
return form
def clean(self):
super().clean()
data = [f.cleaned_data for f in self.forms]
if len([d for d in data if d.get("mode") == KnownDomain.MODE_ORG_DOMAIN and not d.get("DELETE")]) > 1:
raise ValidationError(_("You may set only one organizer domain."))
return data
KnownDomainFormset = inlineformset_factory(
Organizer, KnownDomain,
KnownDomainForm,
formset=BaseKnownDomainFormSet,
can_order=False, can_delete=True, extra=0
)
class SafeOrderPositionChoiceField(forms.ModelChoiceField): class SafeOrderPositionChoiceField(forms.ModelChoiceField):
@@ -22,7 +22,7 @@
{% bootstrap_field form.name layout="control" %} {% bootstrap_field form.name layout="control" %}
{% bootstrap_field form.slug layout="control" %} {% bootstrap_field form.slug layout="control" %}
{% if form.domain %} {% if form.domain %}
{% bootstrap_field form.domain layout="horizontal" %} {% bootstrap_field form.domain layout="control" %}
{% endif %} {% endif %}
{% bootstrap_field form.date_from layout="control" %} {% bootstrap_field form.date_from layout="control" %}
{% bootstrap_field form.date_to layout="control" %} {% bootstrap_field form.date_to layout="control" %}
@@ -26,7 +26,6 @@
{% bootstrap_field form.name layout="control" %} {% bootstrap_field form.name layout="control" %}
{% bootstrap_field form.internal_name layout="control" %} {% bootstrap_field form.internal_name layout="control" %}
{% bootstrap_field form.rate addon_after="%" layout="control" %} {% bootstrap_field form.rate addon_after="%" layout="control" %}
{% bootstrap_field form.code layout="control" %}
{% bootstrap_field form.price_includes_tax layout="control" %} {% bootstrap_field form.price_includes_tax layout="control" %}
</fieldset> </fieldset>
<fieldset> <fieldset>
@@ -53,18 +52,6 @@
{% trans "All of these rules will only apply if an invoice address is set." %} {% trans "All of these rules will only apply if an invoice address is set." %}
</div> </div>
<div class="row">
<div class="col-sm-6 col-md-3 col-lg-3">
<strong>{% trans "Condition" %}</strong>
</div>
<div class="col-sm-6 col-md-3 col-lg-3">
<strong>{% trans "Calculation" %}</strong>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 col-sm-offset-6 col-md-offset-0">
<strong>{% trans "Reason" %}</strong>
</div>
</div>
<div class="formset tax-rules-formset" data-formset data-formset-prefix="{{ formset.prefix }}"> <div class="formset tax-rules-formset" data-formset data-formset-prefix="{{ formset.prefix }}">
{{ formset.management_form }} {{ formset.management_form }}
{% bootstrap_formset_errors formset %} {% bootstrap_formset_errors formset %}
@@ -78,17 +65,14 @@
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-3"> <div class="col-sm-6 col-md-3 col-lg-3">
{% bootstrap_field formset.empty_form.country layout='inline' form_group_class="" %} {% bootstrap_field formset.empty_form.country layout='inline' form_group_class="" %}
</div>
<div class="col-sm-6 col-md-3 col-lg-4">
{% bootstrap_field formset.empty_form.address_type layout='inline' form_group_class="" %} {% bootstrap_field formset.empty_form.address_type layout='inline' form_group_class="" %}
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-3"> <div class="col-sm-6 col-md-3 col-lg-3">
{% bootstrap_field formset.empty_form.action layout='inline' form_group_class="" %} {% bootstrap_field formset.empty_form.action layout='inline' form_group_class="" %}
{% bootstrap_field formset.empty_form.rate layout='inline' form_group_class="" %}
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-4 col-sm-offset-6 col-md-offset-0"> <div class="col-sm-6 col-md-3 col-lg-2 text-right flip">
{% bootstrap_field formset.empty_form.code layout='inline' form_group_class="" %}
{% bootstrap_field formset.empty_form.invoice_text layout='inline' form_group_class="" %}
</div>
<div class="col-sm-6 col-md-3 col-lg-2 col-sm-offset-6 col-md-offset-0 text-right flip">
<button type="button" class="btn btn-default" data-formset-move-up-button> <button type="button" class="btn btn-default" data-formset-move-up-button>
<i class="fa fa-arrow-up"></i></button> <i class="fa fa-arrow-up"></i></button>
<button type="button" class="btn btn-default" data-formset-move-down-button> <button type="button" class="btn btn-default" data-formset-move-down-button>
@@ -96,6 +80,12 @@
<button type="button" class="btn btn-danger" data-formset-delete-button> <button type="button" class="btn btn-danger" data-formset-delete-button>
<i class="fa fa-trash"></i></button> <i class="fa fa-trash"></i></button>
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-4 col-md-offset-3">
{% bootstrap_field formset.empty_form.invoice_text layout='inline' form_group_class="" %}
</div>
<div class="col-sm-6 col-md-3 col-lg-3">
{% bootstrap_field formset.empty_form.rate layout='inline' form_group_class="" %}
</div>
</div> </div>
{% endescapescript %} {% endescapescript %}
</script> </script>
@@ -110,17 +100,14 @@
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-3"> <div class="col-sm-6 col-md-3 col-lg-3">
{% bootstrap_field form.country layout='inline' form_group_class="" %} {% bootstrap_field form.country layout='inline' form_group_class="" %}
</div>
<div class="col-sm-6 col-md-3 col-lg-4">
{% bootstrap_field form.address_type layout='inline' form_group_class="" %} {% bootstrap_field form.address_type layout='inline' form_group_class="" %}
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-3"> <div class="col-sm-6 col-md-3 col-lg-3">
{% bootstrap_field form.action layout='inline' form_group_class="" %} {% bootstrap_field form.action layout='inline' form_group_class="" %}
{% bootstrap_field form.rate layout='inline' form_group_class="" %}
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-4 col-sm-offset-6 col-md-offset-0"> <div class="col-sm-6 col-md-3 col-lg-2 text-right flip">
{% bootstrap_field form.code layout='inline' form_group_class="" %}
{% bootstrap_field form.invoice_text layout='inline' form_group_class="" %}
</div>
<div class="col-sm-6 col-md-3 col-lg-2 col-sm-offset-6 col-md-offset-0 text-right flip">
<button type="button" class="btn btn-default" data-formset-move-up-button> <button type="button" class="btn btn-default" data-formset-move-up-button>
<i class="fa fa-arrow-up"></i></button> <i class="fa fa-arrow-up"></i></button>
<button type="button" class="btn btn-default" data-formset-move-down-button> <button type="button" class="btn btn-default" data-formset-move-down-button>
@@ -128,6 +115,12 @@
<button type="button" class="btn btn-danger" data-formset-delete-button> <button type="button" class="btn btn-danger" data-formset-delete-button>
<i class="fa fa-trash"></i></button> <i class="fa fa-trash"></i></button>
</div> </div>
<div class="col-sm-6 col-md-3 col-lg-4 col-md-offset-3">
{% bootstrap_field form.invoice_text layout='inline' form_group_class="" %}
</div>
<div class="col-sm-6 col-md-3 col-lg-3">
{% bootstrap_field form.rate layout='inline' form_group_class="" %}
</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
@@ -220,6 +220,7 @@
{% endif %} {% endif %}
{% bootstrap_field formset.empty_form.available_from visibility_field=formset.empty_form.available_from_mode layout="control_with_visibility" %} {% bootstrap_field formset.empty_form.available_from visibility_field=formset.empty_form.available_from_mode layout="control_with_visibility" %}
{% bootstrap_field formset.empty_form.available_until visibility_field=formset.empty_form.available_until_mode layout="control_with_visibility" %} {% bootstrap_field formset.empty_form.available_until visibility_field=formset.empty_form.available_until_mode layout="control_with_visibility" %}
{% bootstrap_field formset.empty_form.available_until layout="control" %}
{% bootstrap_field formset.empty_form.all_sales_channels layout="control" %} {% bootstrap_field formset.empty_form.all_sales_channels layout="control" %}
{% bootstrap_field formset.empty_form.limit_sales_channels layout="control" %} {% bootstrap_field formset.empty_form.limit_sales_channels layout="control" %}
{% bootstrap_field formset.empty_form.hide_without_voucher layout="control" %} {% bootstrap_field formset.empty_form.hide_without_voucher layout="control" %}
@@ -202,12 +202,6 @@
+ {{ position.tax_rate }}%) + {{ position.tax_rate }}%)
</small> </small>
{% endif %} {% endif %}
{% if position.tax_code %}
<br>
<small>
{{ position.get_tax_code_display }}
</small>
{% endif %}
</div> </div>
<div class="col-sm-4 field-container"> <div class="col-sm-4 field-container">
{% bootstrap_field position.form.price addon_after=request.event.currency layout='inline' %} {% bootstrap_field position.form.price addon_after=request.event.currency layout='inline' %}
@@ -426,12 +420,6 @@
+ {{ fee.tax_rate }}%) + {{ fee.tax_rate }}%)
</small> </small>
{% endif %} {% endif %}
{% if fee.tax_code %}
<br>
<small>
{{ fee.get_tax_code_display }}
</small>
{% endif %}
</div> </div>
<div class="col-sm-4 field-container"> <div class="col-sm-4 field-container">
{% bootstrap_field fee.form.value addon_after=request.event.currency layout='inline' %} {% bootstrap_field fee.form.value addon_after=request.event.currency layout='inline' %}
@@ -19,7 +19,6 @@
<th>{% trans "Date" %}</th> <th>{% trans "Date" %}</th>
<th>{% trans "Product" %}</th> <th>{% trans "Product" %}</th>
<th class="text-right flip">{% trans "Tax rate" %}</th> <th class="text-right flip">{% trans "Tax rate" %}</th>
<th>{% trans "Tax code" %}</th>
<th class="text-right flip">{% trans "Quantity" %}</th> <th class="text-right flip">{% trans "Quantity" %}</th>
<th class="text-right flip">{% trans "Single price" %}</th> <th class="text-right flip">{% trans "Single price" %}</th>
<th class="text-right flip">{% trans "Total tax value" %}</th> <th class="text-right flip">{% trans "Total tax value" %}</th>
@@ -53,7 +52,6 @@
{% endif %} {% endif %}
</td> </td>
<td class="text-right flip">{{ t.tax_rate }} %</td> <td class="text-right flip">{{ t.tax_rate }} %</td>
<td>{{ t.get_tax_code_display }}</td>
<td class="text-right flip">{{ t.count }} &times;</td> <td class="text-right flip">{{ t.count }} &times;</td>
<td class="text-right flip">{{ t.price|money:request.event.currency }}</td> <td class="text-right flip">{{ t.price|money:request.event.currency }}</td>
<td class="text-right flip">{{ t.full_tax_value|money:request.event.currency }}</td> <td class="text-right flip">{{ t.full_tax_value|money:request.event.currency }}</td>
@@ -66,8 +64,8 @@
<td> <td>
<strong>{% trans "Sum" %}</strong> <strong>{% trans "Sum" %}</strong>
</td> </td>
<td></td> <td>
<td></td> </td>
<td></td> <td></td>
<td class="text-right flip"> <td class="text-right flip">
<strong> <strong>
@@ -294,71 +294,6 @@
<legend>{% trans "Invoices" %}</legend> <legend>{% trans "Invoices" %}</legend>
{% bootstrap_field sform.invoice_regenerate_allowed layout="control" %} {% bootstrap_field sform.invoice_regenerate_allowed layout="control" %}
</fieldset> </fieldset>
{% if domain_formset %}
<fieldset>
<legend>{% trans "Domains" %}</legend>
<div class="alert alert-warning">
{% trans "This dialog is intended for advanced users." %}
{% trans "The domain needs to be configured on your webserver before it can be used here." %}
</div>
<div class="formset" data-formset data-formset-prefix="{{ domain_formset.prefix }}">
{{ domain_formset.management_form }}
{% bootstrap_formset_errors domain_formset %}
<div data-formset-body>
{% for form in domain_formset %}
<div class="row formset-row" data-formset-form>
<div class="sr-only">
{{ form.id }}
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
</div>
<div class="col-md-4">
{% bootstrap_field form.domainname layout='' form_group_class="" %}
{% bootstrap_form_errors form %}
</div>
<div class="col-md-3">
{% bootstrap_field form.mode layout='' form_group_class="" %}
</div>
<div class="col-md-3">
{% bootstrap_field form.event layout='' form_group_class="" %}
</div>
<div class="col-md-2 text-right flip">
<label aria-hidden="true">&nbsp;</label><br>
<button type="button" class="btn btn-danger" data-formset-delete-button>
<i class="fa fa-trash"></i></button>
</div>
</div>
{% endfor %}
</div>
<script type="form-template" data-formset-empty-form>
{% escapescript %}
<div class="row formset-row" data-formset-form>
<div class="sr-only">
{{ domain_formset.empty_form.id }}
{% bootstrap_field domain_formset.empty_form.DELETE form_group_class="" layout="inline" %}
</div>
<div class="col-md-4">
{% bootstrap_field domain_formset.empty_form.domainname layout='' form_group_class="" %}
</div>
<div class="col-md-3">
{% bootstrap_field domain_formset.empty_form.mode layout='' form_group_class="" %}
</div>
<div class="col-md-3">
{% bootstrap_field domain_formset.empty_form.event layout='' form_group_class="" %}
</div>
<div class="col-md-2 text-right flip">
<label aria-hidden="true">&nbsp;</label><br>
<button type="button" class="btn btn-danger" data-formset-delete-button>
<i class="fa fa-trash"></i></button>
</div>
</div>
{% endescapescript %}
</script>
<p>
<button type="button" class="btn btn-default" data-formset-add>
<i class="fa fa-plus"></i> {% trans "Add domain" %}</button>
</p>
</fieldset>
{% endif %}
</div> </div>
<div class="form-group submit-group"> <div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save"> <button type="submit" class="btn btn-primary btn-save">
+8 -11
View File
@@ -38,7 +38,6 @@ from zoneinfo import ZoneInfo
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.humanize.templatetags.humanize import intcomma
from django.db.models import ( from django.db.models import (
Count, IntegerField, Max, Min, OuterRef, Prefetch, Q, Subquery, Sum, Count, IntegerField, Max, Min, OuterRef, Prefetch, Q, Subquery, Sum,
) )
@@ -48,6 +47,7 @@ from django.http import JsonResponse
from django.shortcuts import render from django.shortcuts import render
from django.template.loader import get_template from django.template.loader import get_template
from django.urls import reverse from django.urls import reverse
from django.utils import formats
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.html import escape from django.utils.html import escape
from django.utils.timezone import now from django.utils.timezone import now
@@ -67,7 +67,6 @@ from pretix.control.signals import (
from pretix.helpers.daterange import daterange from pretix.helpers.daterange import daterange
from ...base.models.orders import CancellationRequest from ...base.models.orders import CancellationRequest
from ...base.templatetags.money import money_filter
from ..logdisplay import OVERVIEW_BANLIST from ..logdisplay import OVERVIEW_BANLIST
NUM_WIDGET = '<div class="numwidget"><span class="num">{num}</span><span class="text">{text}</span></div>' NUM_WIDGET = '<div class="numwidget"><span class="num">{num}</span><span class="text">{text}</span></div>'
@@ -112,7 +111,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs):
return [ return [
{ {
'content': None if lazy else NUM_WIDGET.format(num=intcomma(tickc), text=_('Attendees (ordered)')), 'content': None if lazy else NUM_WIDGET.format(num=tickc, text=_('Attendees (ordered)')),
'lazy': 'attendees-ordered', 'lazy': 'attendees-ordered',
'display_size': 'small', 'display_size': 'small',
'priority': 100, 'priority': 100,
@@ -122,7 +121,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs):
}) + ('?subevent={}'.format(subevent.pk) if subevent else '') }) + ('?subevent={}'.format(subevent.pk) if subevent else '')
}, },
{ {
'content': None if lazy else NUM_WIDGET.format(num=intcomma(paidc), text=_('Attendees (paid)')), 'content': None if lazy else NUM_WIDGET.format(num=paidc, text=_('Attendees (paid)')),
'lazy': 'attendees-paid', 'lazy': 'attendees-paid',
'display_size': 'small', 'display_size': 'small',
'priority': 100, 'priority': 100,
@@ -133,9 +132,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs):
}, },
{ {
'content': None if lazy else NUM_WIDGET.format( 'content': None if lazy else NUM_WIDGET.format(
num=money_filter(round_decimal(rev, sender.currency), sender.currency, hide_currency=True), num=formats.localize(round_decimal(rev, sender.currency)), text=_('Total revenue ({currency})').format(currency=sender.currency)),
text=_('Total revenue ({currency})').format(currency=sender.currency)
),
'lazy': 'total-revenue', 'lazy': 'total-revenue',
'display_size': 'small', 'display_size': 'small',
'priority': 100, 'priority': 100,
@@ -210,7 +207,7 @@ def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs):
widgets.append({ widgets.append({
'content': None if lazy else NUM_WIDGET.format( 'content': None if lazy else NUM_WIDGET.format(
num=intcomma(happy), text=_('available to give to people on waiting list') num=str(happy), text=_('available to give to people on waiting list')
), ),
'lazy': 'waitinglist-avail', 'lazy': 'waitinglist-avail',
'priority': 50, 'priority': 50,
@@ -220,7 +217,7 @@ def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs):
}) })
}) })
widgets.append({ widgets.append({
'content': None if lazy else NUM_WIDGET.format(num=intcomma(wles.count()), text=_('total waiting list length')), 'content': None if lazy else NUM_WIDGET.format(num=str(wles.count()), text=_('total waiting list length')),
'lazy': 'waitinglist-length', 'lazy': 'waitinglist-length',
'display_size': 'small', 'display_size': 'small',
'priority': 50, 'priority': 50,
@@ -248,7 +245,7 @@ def quota_widgets(sender, subevent=None, lazy=False, **kwargs):
status, left = qa.results[q] if q in qa.results else q.availability(allow_cache=True) status, left = qa.results[q] if q in qa.results else q.availability(allow_cache=True)
widgets.append({ widgets.append({
'content': None if lazy else NUM_WIDGET.format( 'content': None if lazy else NUM_WIDGET.format(
num='{}/{}'.format(intcomma(left), intcomma(q.size)) if q.size is not None else '\u221e', num='{}/{}'.format(left, q.size) if q.size is not None else '\u221e',
text=_('{quota} left').format(quota=escape(q.name)) text=_('{quota} left').format(quota=escape(q.name))
), ),
'lazy': 'quota-{}'.format(q.pk), 'lazy': 'quota-{}'.format(q.pk),
@@ -300,7 +297,7 @@ def checkin_widget(sender, subevent=None, lazy=False, **kwargs):
for cl in qs: for cl in qs:
widgets.append({ widgets.append({
'content': None if lazy else NUM_WIDGET.format( 'content': None if lazy else NUM_WIDGET.format(
num='{}/{}'.format(intcomma(cl.inside_count), intcomma(cl.position_count)), num='{}/{}'.format(cl.inside_count, cl.position_count),
text=_('Present {list}').format(list=escape(cl.name)) text=_('Present {list}').format(list=escape(cl.name))
), ),
'lazy': 'checkin-{}'.format(cl.pk), 'lazy': 'checkin-{}'.format(cl.pk),
+25 -36
View File
@@ -62,7 +62,7 @@ from django.http import (
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import conditional_escape from django.utils.html import escape
from django.utils.http import url_has_allowed_host_and_scheme from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _, gettext_noop from django.utils.translation import gettext, gettext_lazy as _, gettext_noop
@@ -100,12 +100,9 @@ from ...base.models.items import (
Item, ItemCategory, ItemMetaProperty, Question, Quota, Item, ItemCategory, ItemMetaProperty, Question, Quota,
) )
from ...base.services.mail import prefix_subject from ...base.services.mail import prefix_subject
from ...base.services.placeholders import get_sample_context
from ...base.settings import LazyI18nStringList from ...base.settings import LazyI18nStringList
from ...helpers.compat import CompatDeleteView from ...helpers.compat import CompatDeleteView
from ...helpers.format import ( from ...helpers.format import format_map
PlainHtmlAlternativeString, SafeFormatter, format_map,
)
from ..logdisplay import OVERVIEW_BANLIST from ..logdisplay import OVERVIEW_BANLIST
from . import CreateView, PaginationMixin, UpdateView from . import CreateView, PaginationMixin, UpdateView
@@ -242,6 +239,7 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
if self.request.user.has_active_staff_session(self.request.session.session_key): if self.request.user.has_active_staff_session(self.request.session.session_key):
kwargs['change_slug'] = True kwargs['change_slug'] = True
kwargs['domain'] = True
return kwargs return kwargs
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@@ -719,7 +717,20 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
# get all supported placeholders with dummy values # get all supported placeholders with dummy values
def placeholders(self, item): def placeholders(self, item):
return get_sample_context(self.request.event, MailSettingsForm.base_context[item]) ctx = {}
for p in get_available_placeholders(self.request.event, MailSettingsForm.base_context[item]).values():
s = str(p.render_sample(self.request.event))
if s.strip().startswith('* '):
ctx[p.identifier] = '<div class="placeholder" title="{}">{}</div>'.format(
_('This value will be replaced based on dynamic parameters.'),
markdown_compile_email(s)
)
else:
ctx[p.identifier] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'),
escape(s)
)
return ctx
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
preview_item = request.POST.get('item', '') preview_item = request.POST.get('item', '')
@@ -741,15 +752,9 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
bleach.clean(v), self.placeholders(preview_item), raise_on_missing=True bleach.clean(v), self.placeholders(preview_item), raise_on_missing=True
), highlight=True) ), highlight=True)
else: else:
placeholders = self.placeholders(preview_item) msgs[self.supported_locale[idx]] = markdown_compile_email(
msgs[self.supported_locale[idx]] = format_map( format_map(v, self.placeholders(preview_item), raise_on_missing=True)
markdown_compile_email(
format_map(v, placeholders, raise_on_missing=True)
),
placeholders,
mode=SafeFormatter.MODE_RICH_TO_HTML,
) )
except ValueError: except ValueError:
msgs[self.supported_locale[idx]] = '<div class="alert alert-danger">{}</div>'.format( msgs[self.supported_locale[idx]] = '<div class="alert alert-danger">{}</div>'.format(
PlaceholderValidator.error_message) PlaceholderValidator.error_message)
@@ -772,18 +777,13 @@ class MailSettingsRendererPreview(MailSettingsPreview):
# get all supported placeholders with dummy values # get all supported placeholders with dummy values
def placeholders(self, item): def placeholders(self, item):
ctx = {} ctx = {}
for p in get_available_placeholders(self.request.event, MailSettingsForm.base_context[item], rich=True).values(): for p in get_available_placeholders(self.request.event, MailSettingsForm.base_context[item]).values():
sample = p.render_sample(self.request.event) ctx[p.identifier] = escape(str(p.render_sample(self.request.event)))
if isinstance(sample, PlainHtmlAlternativeString):
ctx[p.identifier] = sample
else:
ctx[p.identifier] = conditional_escape(sample)
return ctx return ctx
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
v = str(request.event.settings.mail_text_order_placed) v = str(request.event.settings.mail_text_order_placed)
context = self.placeholders('mail_text_order_placed') v = format_map(v, self.placeholders('mail_text_order_placed'))
v = format_map(v, context)
renderers = request.event.get_html_mail_renderers() renderers = request.event.get_html_mail_renderers()
if request.GET.get('renderer') in renderers: if request.GET.get('renderer') in renderers:
with rolledback_transaction(): with rolledback_transaction():
@@ -801,8 +801,7 @@ class MailSettingsRendererPreview(MailSettingsPreview):
str(request.event.settings.mail_text_signature), str(request.event.settings.mail_text_signature),
gettext('Your order: %(code)s') % {'code': order.code}, gettext('Your order: %(code)s') % {'code': order.code},
order, order,
position=None, position=None
context=context,
) )
r = HttpResponse(v, content_type='text/html') r = HttpResponse(v, content_type='text/html')
r._csp_ignore = True r._csp_ignore = True
@@ -1197,22 +1196,17 @@ class TaxCreate(EventSettingsViewMixin, EventPermissionRequiredMixin, CreateView
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.object = None self.object = None
form = self.form form = self.get_form()
if form.is_valid() and self.formset.is_valid(): if form.is_valid() and self.formset.is_valid():
return self.form_valid(form) return self.form_valid(form)
else: else:
return self.form_invalid(form) return self.form_invalid(form)
@cached_property
def form(self):
return self.get_form()
@cached_property @cached_property
def formset(self): def formset(self):
return TaxRuleLineFormSet( return TaxRuleLineFormSet(
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,
parent_form=self.form,
) )
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@@ -1253,22 +1247,17 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.object = self.get_object(self.get_queryset()) self.object = self.get_object(self.get_queryset())
form = self.form form = self.get_form()
if form.is_valid() and self.formset.is_valid(): if form.is_valid() and self.formset.is_valid():
return self.form_valid(form) return self.form_valid(form)
else: else:
return self.form_invalid(form) return self.form_invalid(form)
@cached_property
def form(self):
return self.get_form()
@cached_property @cached_property
def formset(self): def formset(self):
return TaxRuleLineFormSet( return TaxRuleLineFormSet(
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,
parent_form=self.form,
initial=json.loads(self.object.custom_rules) if self.object.custom_rules else [] initial=json.loads(self.object.custom_rules) if self.object.custom_rules else []
) )
+2 -4
View File
@@ -134,7 +134,7 @@ from pretix.control.signals import order_search_forms
from pretix.control.views import PaginationMixin from pretix.control.views import PaginationMixin
from pretix.helpers import OF_SELF from pretix.helpers import OF_SELF
from pretix.helpers.compat import CompatDeleteView from pretix.helpers.compat import CompatDeleteView
from pretix.helpers.format import SafeFormatter, format_map from pretix.helpers.format import format_map
from pretix.helpers.safedownload import check_token from pretix.helpers.safedownload import check_token
from pretix.presale.signals import question_form_fields from pretix.presale.signals import question_form_fields
@@ -2241,8 +2241,6 @@ class OrderContactChange(OrderView):
changed = True changed = True
self.order.secret = generate_secret() self.order.secret = generate_secret()
for op in self.order.all_positions.all(): for op in self.order.all_positions.all():
op.web_secret = generate_secret()
op.save(update_fields=["web_secret"])
assign_ticket_secret( assign_ticket_secret(
self.request.event, position=op, force_invalidate=True, save=True self.request.event, position=op, force_invalidate=True, save=True
) )
@@ -2353,7 +2351,7 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
'subject': mark_safe(_('Subject: {subject}').format( 'subject': mark_safe(_('Subject: {subject}').format(
subject=prefix_subject(order.event, escape(email_subject), highlight=True) subject=prefix_subject(order.event, escape(email_subject), highlight=True)
)), )),
'html': format_map(markdown_compile_email(email_content), email_context, mode=SafeFormatter.MODE_RICH_TO_HTML) 'html': markdown_compile_email(email_content)
} }
return self.get(self.request, *self.args, **self.kwargs) return self.get(self.request, *self.args, **self.kwargs)
else: else:
+11 -37
View File
@@ -104,11 +104,11 @@ from pretix.control.forms.organizer import (
CustomerCreateForm, CustomerUpdateForm, DeviceBulkEditForm, DeviceForm, CustomerCreateForm, CustomerUpdateForm, DeviceBulkEditForm, DeviceForm,
EventMetaPropertyAllowedValueFormSet, EventMetaPropertyForm, GateForm, EventMetaPropertyAllowedValueFormSet, EventMetaPropertyForm, GateForm,
GiftCardAcceptanceInviteForm, GiftCardCreateForm, GiftCardUpdateForm, GiftCardAcceptanceInviteForm, GiftCardCreateForm, GiftCardUpdateForm,
KnownDomainFormset, MailSettingsForm, MembershipTypeForm, MailSettingsForm, MembershipTypeForm, MembershipUpdateForm,
MembershipUpdateForm, OrganizerDeleteForm, OrganizerFooterLinkFormset, OrganizerDeleteForm, OrganizerFooterLinkFormset, OrganizerForm,
OrganizerForm, OrganizerSettingsForm, OrganizerUpdateForm, OrganizerSettingsForm, OrganizerUpdateForm, ReusableMediumCreateForm,
ReusableMediumCreateForm, ReusableMediumUpdateForm, SalesChannelForm, ReusableMediumUpdateForm, SalesChannelForm, SSOClientForm, SSOProviderForm,
SSOClientForm, SSOProviderForm, TeamForm, WebHookForm, TeamForm, WebHookForm,
) )
from pretix.control.forms.rrule import RRuleForm from pretix.control.forms.rrule import RRuleForm
from pretix.control.logdisplay import OVERVIEW_BANLIST from pretix.control.logdisplay import OVERVIEW_BANLIST
@@ -122,7 +122,7 @@ from pretix.control.views.mailsetup import MailSettingsSetupView
from pretix.helpers import OF_SELF, GroupConcat from pretix.helpers import OF_SELF, GroupConcat
from pretix.helpers.compat import CompatDeleteView from pretix.helpers.compat import CompatDeleteView
from pretix.helpers.dicts import merge_dicts from pretix.helpers.dicts import merge_dicts
from pretix.helpers.format import SafeFormatter, format_map from pretix.helpers.format import format_map
from pretix.helpers.urls import build_absolute_uri as build_global_uri from pretix.helpers.urls import build_absolute_uri as build_global_uri
from pretix.multidomain.urlreverse import build_absolute_uri from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.presale.forms.customer import TokenGenerator from pretix.presale.forms.customer import TokenGenerator
@@ -357,10 +357,9 @@ class MailSettingsPreview(OrganizerPermissionRequiredMixin, View):
highlight=True, highlight=True,
) )
else: else:
placeholders = self.placeholders(preview_item) msgs[self.supported_locale[idx]] = markdown_compile_email(
msgs[self.supported_locale[idx]] = format_map(markdown_compile_email( format_map(v, self.placeholders(preview_item))
format_map(v, placeholders) )
), placeholders, mode=SafeFormatter.MODE_RICH_TO_HTML)
return JsonResponse({ return JsonResponse({
'item': preview_item, 'item': preview_item,
@@ -448,10 +447,6 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
def get_object(self, queryset=None) -> Organizer: def get_object(self, queryset=None) -> Organizer:
return self.object return self.object
@cached_property
def domain_config(self):
return self.request.user.has_active_staff_session(self.request.session.session_key)
@cached_property @cached_property
def sform(self): def sform(self):
return OrganizerSettingsForm( return OrganizerSettingsForm(
@@ -466,8 +461,6 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
context['sform'] = self.sform context['sform'] = self.sform
context['footer_links_formset'] = self.footer_links_formset context['footer_links_formset'] = self.footer_links_formset
if self.domain_config:
context['domain_formset'] = self.domain_formset
return context return context
@transaction.atomic @transaction.atomic
@@ -490,8 +483,6 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
self.request.organizer.log_action('pretix.organizer.footerlinks.changed', user=self.request.user, data={ self.request.organizer.log_action('pretix.organizer.footerlinks.changed', user=self.request.user, data={
'data': self.footer_links_formset.cleaned_data 'data': self.footer_links_formset.cleaned_data
}) })
if self.domain_config and self.domain_formset.has_changed():
self._save_domain_config()
if form.has_changed(): if form.has_changed():
self.request.organizer.log_action( self.request.organizer.log_action(
'pretix.organizer.changed', 'pretix.organizer.changed',
@@ -502,22 +493,10 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
messages.success(self.request, _('Your changes have been saved.')) messages.success(self.request, _('Your changes have been saved.'))
return super().form_valid(form) return super().form_valid(form)
def _save_domain_config(self):
for form in self.domain_formset.initial_forms:
if form.instance.pk and form.has_changed():
self.object.domains.get(pk=form.instance.pk).log_delete(self.request.user)
self.domain_formset.save()
for new_obj in self.domain_formset.new_objects:
new_obj.log_create(self.request.user)
for ch_obj, form in self.domain_formset.changed_objects:
ch_obj.log_create(self.request.user)
self.request.organizer.cache.clear()
for ev in self.request.organizer.events.all():
ev.cache.clear()
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
if self.request.user.has_active_staff_session(self.request.session.session_key): if self.request.user.has_active_staff_session(self.request.session.session_key):
kwargs['domain'] = True
kwargs['change_slug'] = True kwargs['change_slug'] = True
return kwargs return kwargs
@@ -529,7 +508,7 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
form = self.get_form() form = self.get_form()
if form.is_valid() and self.sform.is_valid() and self.footer_links_formset.is_valid() and (not self.domain_config or self.domain_formset.is_valid()): if form.is_valid() and self.sform.is_valid() and self.footer_links_formset.is_valid():
return self.form_valid(form) return self.form_valid(form)
else: else:
return self.form_invalid(form) return self.form_invalid(form)
@@ -540,11 +519,6 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
organizer=self.object, organizer=self.object,
prefix="footer-links", instance=self.object) prefix="footer-links", instance=self.object)
@cached_property
def domain_formset(self):
return KnownDomainFormset(self.request.POST if self.request.method == "POST" else None, prefix="domains",
instance=self.object, organizer=self.object)
def save_footer_links_formset(self, obj): def save_footer_links_formset(self, obj):
self.footer_links_formset.save() self.footer_links_formset.save()
+19 -8
View File
@@ -50,7 +50,7 @@ from django.http import (
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.urls import resolve, reverse from django.urls import resolve, reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.html import format_html from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -59,12 +59,12 @@ from django.views.generic import (
) )
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from pretix.base.email import get_available_placeholders
from pretix.base.models import ( from pretix.base.models import (
CartPosition, LogEntry, Voucher, WaitingListEntry, CartPosition, LogEntry, Voucher, WaitingListEntry,
) )
from pretix.base.models.vouchers import generate_codes from pretix.base.models.vouchers import generate_codes
from pretix.base.services.mail import prefix_subject from pretix.base.services.mail import prefix_subject
from pretix.base.services.placeholders import get_sample_context
from pretix.base.services.vouchers import vouchers_send from pretix.base.services.vouchers import vouchers_send
from pretix.base.templatetags.rich_text import markdown_compile_email from pretix.base.templatetags.rich_text import markdown_compile_email
from pretix.base.views.tasks import AsyncFormView from pretix.base.views.tasks import AsyncFormView
@@ -74,7 +74,7 @@ from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.signals import voucher_form_class from pretix.control.signals import voucher_form_class
from pretix.control.views import PaginationMixin from pretix.control.views import PaginationMixin
from pretix.helpers.compat import CompatDeleteView from pretix.helpers.compat import CompatDeleteView
from pretix.helpers.format import SafeFormatter, format_map from pretix.helpers.format import format_map
from pretix.helpers.models import modelcopy from pretix.helpers.models import modelcopy
from pretix.multidomain.urlreverse import build_absolute_uri from pretix.multidomain.urlreverse import build_absolute_uri
@@ -549,10 +549,22 @@ class VoucherBulkMailPreview(EventPermissionRequiredMixin, View):
# get all supported placeholders with dummy values # get all supported placeholders with dummy values
def placeholders(self, item): def placeholders(self, item):
ctx = {}
base_ctx = ['event', 'name'] base_ctx = ['event', 'name']
if item == 'send_message': if item == 'send_message':
base_ctx += ['voucher_list'] base_ctx += ['voucher_list']
ctx = get_sample_context(self.request.event, base_ctx) for p in get_available_placeholders(self.request.event, base_ctx).values():
s = str(p.render_sample(self.request.event))
if s.strip().startswith('* ') or s.startswith(' '):
ctx[p.identifier] = '<div class="placeholder" title="{}">{}</div>'.format(
_('This value will be replaced based on dynamic parameters.'),
markdown_compile_email(s)
)
else:
ctx[p.identifier] = '<span class="placeholder" title="{}">{}</span>'.format(
_('This value will be replaced based on dynamic parameters.'),
escape(s)
)
return self.SafeDict(ctx) return self.SafeDict(ctx)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@@ -567,10 +579,9 @@ class VoucherBulkMailPreview(EventPermissionRequiredMixin, View):
highlight=True highlight=True
) )
else: else:
placeholders = self.placeholders(preview_item) msgs["all"] = markdown_compile_email(
msgs["all"] = format_map(markdown_compile_email( format_map(request.POST.get(preview_item), self.placeholders(preview_item))
format_map(request.POST.get(preview_item), placeholders) )
), placeholders, mode=SafeFormatter.MODE_RICH_TO_HTML)
return JsonResponse({ return JsonResponse({
'item': preview_item, 'item': preview_item,
+5 -28
View File
@@ -25,29 +25,14 @@ from string import Formatter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class PlainHtmlAlternativeString:
def __init__(self, plain, html, is_block=False):
self.plain = plain
self.html = html
self.is_block = is_block
def __repr__(self):
return f"PlainHtmlAlternativeString('{self.plain}', '{self.html}')"
class SafeFormatter(Formatter): class SafeFormatter(Formatter):
""" """
Customized version of ``str.format`` that (a) behaves just like ``str.format_map`` and Customized version of ``str.format`` that (a) behaves just like ``str.format_map`` and
(b) does not allow any unwanted shenanigans like attribute access or format specifiers. (b) does not allow any unwanted shenanigans like attribute access or format specifiers.
""" """
MODE_IGNORE_RICH = 0 def __init__(self, context, raise_on_missing=False):
MODE_RICH_TO_PLAIN = 1
MODE_RICH_TO_HTML = 2
def __init__(self, context, raise_on_missing=False, mode=MODE_IGNORE_RICH):
self.context = context self.context = context
self.raise_on_missing = raise_on_missing self.raise_on_missing = raise_on_missing
self.mode = mode
def get_field(self, field_name, args, kwargs): def get_field(self, field_name, args, kwargs):
return self.get_value(field_name, args, kwargs), field_name return self.get_value(field_name, args, kwargs), field_name
@@ -55,22 +40,14 @@ class SafeFormatter(Formatter):
def get_value(self, key, args, kwargs): def get_value(self, key, args, kwargs):
if not self.raise_on_missing and key not in self.context: if not self.raise_on_missing and key not in self.context:
return '{' + str(key) + '}' return '{' + str(key) + '}'
r = self.context[key] return self.context[key]
if isinstance(r, PlainHtmlAlternativeString):
if self.mode == self.MODE_IGNORE_RICH:
return '{' + str(key) + '}'
elif self.mode == self.MODE_RICH_TO_PLAIN:
return r.plain
elif self.mode == self.MODE_RICH_TO_HTML:
return r.html
return r
def format_field(self, value, format_spec): def format_field(self, value, format_spec):
# Ignore format_spec # Ignore format _spec
return super().format_field(value, '') return super().format_field(value, '')
def format_map(template, context, raise_on_missing=False, mode=SafeFormatter.MODE_IGNORE_RICH): def format_map(template, context, raise_on_missing=False):
if not isinstance(template, str): if not isinstance(template, str):
template = str(template) template = str(template)
return SafeFormatter(context, raise_on_missing, mode=mode).format(template) return SafeFormatter(context, raise_on_missing).format(template)
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+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"
@@ -622,40 +622,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -705,20 +705,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2021-09-15 11:22+0000\n" "PO-Revision-Date: 2021-09-15 11:22+0000\n"
"Last-Translator: Mohamed Tawfiq <mtawfiq@wafyapp.com>\n" "Last-Translator: Mohamed Tawfiq <mtawfiq@wafyapp.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -656,40 +656,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "تباين اللون سيئ للخلفية البيضاء، الرجاء اختيار لون غامق." msgstr "تباين اللون سيئ للخلفية البيضاء، الرجاء اختيار لون غامق."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "البحث في الاستفسارات" msgstr "البحث في الاستفسارات"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "الكل" msgstr "الكل"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "لا شيء" msgstr "لا شيء"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "المختارة فقط" msgstr "المختارة فقط"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "قم باستخدم اسم مختلف داخليا" msgstr "قم باستخدم اسم مختلف داخليا"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "اضغط لاغلاق الصفحة" msgstr "اضغط لاغلاق الصفحة"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "لم تقم بحفظ التعديلات!" msgstr "لم تقم بحفظ التعديلات!"
@@ -753,20 +753,20 @@ msgstr "ستسترد %(currency)%(amount)"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "الرجاء إدخال المبلغ الذي يمكن للمنظم الاحتفاظ به." msgstr "الرجاء إدخال المبلغ الذي يمكن للمنظم الاحتفاظ به."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "الرجاء إدخال عدد لأحد أنواع التذاكر." msgstr "الرجاء إدخال عدد لأحد أنواع التذاكر."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "مطلوب" msgstr "مطلوب"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "المنطقة الزمنية:" msgstr "المنطقة الزمنية:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "التوقيت المحلي:" msgstr "التوقيت المحلي:"
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2020-12-19 07:00+0000\n" "PO-Revision-Date: 2020-12-19 07:00+0000\n"
"Last-Translator: albert <albert.serra.monner@gmail.com>\n" "Last-Translator: albert <albert.serra.monner@gmail.com>\n"
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -623,40 +623,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -710,22 +710,22 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
#, fuzzy #, fuzzy
#| msgid "Cart expired" #| msgid "Cart expired"
msgid "required" msgid "required"
msgstr "Cistella expirada" msgstr "Cistella expirada"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2023-09-15 06:00+0000\n" "PO-Revision-Date: 2023-09-15 06:00+0000\n"
"Last-Translator: Michael <michael.happl@gmx.at>\n" "Last-Translator: Michael <michael.happl@gmx.at>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -650,40 +650,40 @@ msgstr ""
"Tato barva je pro text na bílém pozadí špatně kontrastní, zvolte prosím " "Tato barva je pro text na bílém pozadí špatně kontrastní, zvolte prosím "
"tmavší odstín." "tmavší odstín."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Hledaný výraz" msgstr "Hledaný výraz"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Všechny" msgstr "Všechny"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Žádný" msgstr "Žádný"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Pouze vybrané" msgstr "Pouze vybrané"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Interně používat jiný název" msgstr "Interně používat jiný název"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Kliknutím zavřete" msgstr "Kliknutím zavřete"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Máte neuložené změny!" msgstr "Máte neuložené změny!"
@@ -740,20 +740,20 @@ msgstr "Dostanete %(currency)s %(amount)s zpět"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Zadejte částku, kterou si organizátor může ponechat." msgstr "Zadejte částku, kterou si organizátor může ponechat."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Zadejte prosím množství pro jeden z typů vstupenek." msgstr "Zadejte prosím množství pro jeden z typů vstupenek."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "povinný" msgstr "povinný"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Časové pásmo:" msgstr "Časové pásmo:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Místní čas:" msgstr "Místní čas:"
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+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"
@@ -623,40 +623,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -706,20 +706,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-10 15:00+0000\n" "PO-Revision-Date: 2024-07-10 15:00+0000\n"
"Last-Translator: Nikolai <nikolai@lengefeldt.de>\n" "Last-Translator: Nikolai <nikolai@lengefeldt.de>\n"
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -670,40 +670,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Ingen" msgstr "Ingen"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Klik for at lukke" msgstr "Klik for at lukke"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Du har ændringer, der ikke er gemt!" msgstr "Du har ændringer, der ikke er gemt!"
@@ -763,22 +763,22 @@ msgstr "fra %(currency)s %(price)s"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
#, fuzzy #, fuzzy
#| msgid "Cart expired" #| msgid "Cart expired"
msgid "required" msgid "required"
msgstr "Kurv udløbet" msgstr "Kurv udløbet"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Tidszone:" msgstr "Tidszone:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Din lokaltid:" msgstr "Din lokaltid:"
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-09-10 07:17+0000\n" "PO-Revision-Date: 2024-09-10 07:17+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/"
@@ -644,40 +644,40 @@ msgstr ""
"Diese Farbe hat einen schlechten Kontrast für Text auf einem weißen " "Diese Farbe hat einen schlechten Kontrast für Text auf einem weißen "
"Hintergrund. Bitte wählen Sie eine dunklere Farbe." "Hintergrund. Bitte wählen Sie eine dunklere Farbe."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Suchbegriff" msgstr "Suchbegriff"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Keine" msgstr "Keine"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Nur ausgewählte" msgstr "Nur ausgewählte"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Geben Sie eine Seitenzahl zwischen 1 und %(max)s ein." msgstr "Geben Sie eine Seitenzahl zwischen 1 und %(max)s ein."
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Ungültige Seitenzahl." msgstr "Ungültige Seitenzahl."
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden" msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Klicken zum Schließen" msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Sie haben ungespeicherte Änderungen!" msgstr "Sie haben ungespeicherte Änderungen!"
@@ -732,20 +732,20 @@ msgstr "Sie erhalten %(currency)s %(amount)s zurück"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Bitte geben Sie den Betrag ein, den der Veranstalter einbehalten darf." msgstr "Bitte geben Sie den Betrag ein, den der Veranstalter einbehalten darf."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Bitte tragen Sie eine Menge für eines der Produkte ein." msgstr "Bitte tragen Sie eine Menge für eines der Produkte ein."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "verpflichtend" msgstr "verpflichtend"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Zeitzone:" msgstr "Zeitzone:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Deine lokale Zeit:" msgstr "Deine lokale Zeit:"
-11
View File
@@ -66,12 +66,10 @@ BSD
bspw bspw
Bokmål Bokmål
Boleto Boleto
Buchhaltungs
Bundles Bundles
Butterfly Butterfly
bzw bzw
ca ca
Ceuta
Cc Cc
chardet chardet
charge charge
@@ -160,12 +158,9 @@ Inc
inkl inkl
innenname innenname
innennamen innennamen
innergemeinschaftliche
Innergemeinschaftlicher
Input Input
Installations Installations
integrationen integrationen
intra
INV INV
invalidieren invalidieren
invalidiert invalidiert
@@ -182,12 +177,10 @@ Kombitickets
Kompatibilitätsmodus Kompatibilitätsmodus
Konfigurations Konfigurations
Kosovo Kosovo
land
landesspezifische landesspezifische
Lead Lead
Leaflet Leaflet
Linktext Linktext
lit
Logindaten Logindaten
Lösch Lösch
loszulegen loszulegen
@@ -195,7 +188,6 @@ Ltd
max max
MariaDB MariaDB
MapQuest MapQuest
Melilla
Mercado Mercado
Merchandise Merchandise
Meta Meta
@@ -277,7 +269,6 @@ rückabgewickelt
Rundungsdifferenzen Rundungsdifferenzen
Sa Sa
Saalplan Saalplan
Sammlungsstücken
SAQ SAQ
SCA SCA
Scan Scan
@@ -366,7 +357,6 @@ USt
Überzahlten Überzahlten
Validierung Validierung
Venmo Venmo
Veranstalterdomain
Veranstaltereinstellungen Veranstaltereinstellungen
Veranstalterkonten Veranstalterkonten
Veranstalterkonto Veranstalterkonto
@@ -377,7 +367,6 @@ Veranstalterseite
Veranstalterübersicht Veranstalterübersicht
veranstalterweiten veranstalterweiten
Veranstaltungs Veranstaltungs
Veranstalterdomain
veranstaltungsweiten veranstaltungsweiten
Verfügbarkeitsberechnung Verfügbarkeitsberechnung
Verfügbarkeitsstatus Verfügbarkeitsstatus
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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-09-10 07:17+0000\n" "PO-Revision-Date: 2024-09-10 07:17+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/"
@@ -643,40 +643,40 @@ msgstr ""
"Diese Farbe hat einen schlechten Kontrast für Text auf einem weißen " "Diese Farbe hat einen schlechten Kontrast für Text auf einem weißen "
"Hintergrund. Bitte wähle eine dunklere Farbe." "Hintergrund. Bitte wähle eine dunklere Farbe."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Suchbegriff" msgstr "Suchbegriff"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Keine" msgstr "Keine"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Nur ausgewählte" msgstr "Nur ausgewählte"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Gib eine Seitenzahl zwischen 1 und %(max)s ein." msgstr "Gib eine Seitenzahl zwischen 1 und %(max)s ein."
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Ungültige Seitenzahl." msgstr "Ungültige Seitenzahl."
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden" msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Klicken zum Schließen" msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Du hast ungespeicherte Änderungen!" msgstr "Du hast ungespeicherte Änderungen!"
@@ -731,20 +731,20 @@ msgstr "Du erhältst %(currency)s %(amount)s zurück"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Bitte gib den Betrag ein, den der Veranstalter einbehalten darf." msgstr "Bitte gib den Betrag ein, den der Veranstalter einbehalten darf."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Bitte trage eine Menge für eines der Produkte ein." msgstr "Bitte trage eine Menge für eines der Produkte ein."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "verpflichtend" msgstr "verpflichtend"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Zeitzone:" msgstr "Zeitzone:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Deine lokale Zeit:" msgstr "Deine lokale Zeit:"
@@ -66,12 +66,10 @@ BSD
bspw bspw
Bokmål Bokmål
Boleto Boleto
Buchhaltungs
Bundles Bundles
Butterfly Butterfly
bzw bzw
ca ca
Ceuta
Cc Cc
chardet chardet
charge charge
@@ -160,12 +158,9 @@ Inc
inkl inkl
innenname innenname
innennamen innennamen
innergemeinschaftliche
Innergemeinschaftlicher
Input Input
Installations Installations
integrationen integrationen
intra
INV INV
invalidieren invalidieren
invalidiert invalidiert
@@ -182,12 +177,10 @@ Kombitickets
Kompatibilitätsmodus Kompatibilitätsmodus
Konfigurations Konfigurations
Kosovo Kosovo
land
landesspezifische landesspezifische
Lead Lead
Leaflet Leaflet
Linktext Linktext
lit
Logindaten Logindaten
Lösch Lösch
loszulegen loszulegen
@@ -195,7 +188,6 @@ Ltd
max max
MariaDB MariaDB
MapQuest MapQuest
Melilla
Mercado Mercado
Merchandise Merchandise
Meta Meta
@@ -277,7 +269,6 @@ rückabgewickelt
Rundungsdifferenzen Rundungsdifferenzen
Sa Sa
Saalplan Saalplan
Sammlungsstücken
SAQ SAQ
SCA SCA
Scan Scan
@@ -366,7 +357,6 @@ USt
Überzahlten Überzahlten
Validierung Validierung
Venmo Venmo
Veranstalterdomain
Veranstaltereinstellungen Veranstaltereinstellungen
Veranstalterkonten Veranstalterkonten
Veranstalterkonto Veranstalterkonto
@@ -377,7 +367,6 @@ Veranstalterseite
Veranstalterübersicht Veranstalterübersicht
veranstalterweiten veranstalterweiten
Veranstaltungs Veranstaltungs
Veranstalterdomain
veranstaltungsweiten veranstaltungsweiten
Verfügbarkeitsberechnung Verfügbarkeitsberechnung
Verfügbarkeitsstatus Verfügbarkeitsstatus
+1844 -2117
View File
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-19 15:34+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"
@@ -622,40 +622,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -705,20 +705,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+29 -25
View File
@@ -7,9 +7,9 @@ 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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-12-22 00:00+0000\n" "PO-Revision-Date: 2019-10-03 19:00+0000\n"
"Last-Translator: Dimitris Tsimpidis <tsimpidisd@gmail.com>\n" "Last-Translator: Chris Spy <chrispiropoulou@hotmail.com>\n"
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
"el/>\n" "el/>\n"
"Language: el\n" "Language: el\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 5.9.2\n" "X-Generator: Weblate 3.5.1\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
@@ -31,7 +31,7 @@ msgstr "Σχόλιο:"
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:34 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:34
msgid "PayPal" msgid "PayPal"
msgstr "PayPal" msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:35 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:35
msgid "Venmo" msgid "Venmo"
@@ -64,7 +64,7 @@ msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:42 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:42
msgid "SEPA Direct Debit" msgid "SEPA Direct Debit"
msgstr "Τραπεζική μεταφορά" msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:43 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:43
msgid "Bancontact" msgid "Bancontact"
@@ -79,8 +79,10 @@ msgid "SOFORT"
msgstr "" msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:46 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:46
#, fuzzy
#| msgid "Yes"
msgid "eps" msgid "eps"
msgstr "EPS" msgstr "Ναι"
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:47 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:47
msgid "MyBank" msgid "MyBank"
@@ -145,11 +147,11 @@ msgstr "Συνέχεια"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:317 #: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:317
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:341 #: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:341
msgid "Confirming your payment …" msgid "Confirming your payment …"
msgstr "Επιβεβαίωση πληρωμής…" msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:254 #: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:254
msgid "Payment method unavailable" msgid "Payment method unavailable"
msgstr "Μη διαθέσιμος τρόπος πληρωμής" msgstr ""
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15 #: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39 #: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
@@ -174,8 +176,10 @@ msgid "Total"
msgstr "Σύνολο" msgstr "Σύνολο"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:291 #: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:291
#, fuzzy
#| msgid "Contacting Stripe …"
msgid "Contacting your bank …" msgid "Contacting your bank …"
msgstr "Επικοινωνία με την τράπεζα …" msgstr "Επικοινωνία με το Stripe …"
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:30 #: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:30
msgid "Select a check-in list" msgid "Select a check-in list"
@@ -682,40 +686,40 @@ msgstr ""
"Το χρώμα σας έχει κακή αντίθεση για κείμενο σε λευκό φόντο, επιλέξτε μια πιο " "Το χρώμα σας έχει κακή αντίθεση για κείμενο σε λευκό φόντο, επιλέξτε μια πιο "
"σκούρα σκιά." "σκούρα σκιά."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Όλα" msgstr "Όλα"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Κανένας" msgstr "Κανένας"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά" msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Κάντε κλικ για να κλείσετε" msgstr "Κάντε κλικ για να κλείσετε"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -777,22 +781,22 @@ msgstr "απο %(currency)s %(price)s"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Εισαγάγετε μια ποσότητα για έναν από τους τύπους εισιτηρίων." msgstr "Εισαγάγετε μια ποσότητα για έναν από τους τύπους εισιτηρίων."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
#, fuzzy #, fuzzy
#| msgid "Cart expired" #| msgid "Cart expired"
msgid "required" msgid "required"
msgstr "Το καλάθι έληξε" msgstr "Το καλάθι έληξε"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+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"
@@ -622,40 +622,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -705,20 +705,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -7,11 +7,11 @@ 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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-11-18 15:48+0000\n" "PO-Revision-Date: 2024-11-18 15:48+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n" "Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/"
"js/es/>\n" "pretix-js/es/>\n"
"Language: es\n" "Language: es\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -642,40 +642,40 @@ msgstr ""
"Tu color tiene mal contraste para un texto con fondo blanco, por favor, " "Tu color tiene mal contraste para un texto con fondo blanco, por favor, "
"escoge un tono más oscuro." "escoge un tono más oscuro."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Consulta de búsqueda" msgstr "Consulta de búsqueda"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Todos" msgstr "Todos"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Ninguno" msgstr "Ninguno"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Solamente seleccionados" msgstr "Solamente seleccionados"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Introduce un número de página entre 1 y %(max)s." msgstr "Introduce un número de página entre 1 y %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Número de página inválido." msgstr "Número de página inválido."
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Usar un nombre diferente internamente" msgstr "Usar un nombre diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Click para cerrar" msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "¡Tienes cambios sin guardar!" msgstr "¡Tienes cambios sin guardar!"
@@ -730,20 +730,20 @@ msgstr "Obtienes %(currency)s %(price)s de vuelta"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Por favor, ingrese el importe que el organizador puede quedarse." msgstr "Por favor, ingrese el importe que el organizador puede quedarse."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Por favor, introduzca un valor para cada tipo de entrada." msgstr "Por favor, introduzca un valor para cada tipo de entrada."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "campo requerido" msgstr "campo requerido"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Zona horaria:" msgstr "Zona horaria:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Su hora local:" msgstr "Su hora local:"
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+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"
@@ -622,40 +622,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -705,20 +705,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-09-06 08:47+0000\n" "PO-Revision-Date: 2024-09-06 08:47+0000\n"
"Last-Translator: Albizuri <oier@puntu.eus>\n" "Last-Translator: Albizuri <oier@puntu.eus>\n"
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -635,40 +635,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Guztiak" msgstr "Guztiak"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -721,20 +721,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2021-11-10 05:00+0000\n" "PO-Revision-Date: 2021-11-10 05:00+0000\n"
"Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n" "Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n"
"Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -651,40 +651,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Kaikki" msgstr "Kaikki"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Käytä toista nimeä sisäisesti" msgstr "Käytä toista nimeä sisäisesti"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Sulje klikkaamalla" msgstr "Sulje klikkaamalla"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Sinulla on tallentamattomia muutoksia!" msgstr "Sinulla on tallentamattomia muutoksia!"
@@ -738,22 +738,22 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
#, fuzzy #, fuzzy
#| msgid "Cart expired" #| msgid "Cart expired"
msgid "required" msgid "required"
msgstr "Ostoskori on vanhentunut" msgstr "Ostoskori on vanhentunut"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Aikavyöhyke:" msgstr "Aikavyöhyke:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+19 -19
View File
@@ -6,8 +6,8 @@ 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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-12-03 20:00+0000\n" "PO-Revision-Date: 2024-11-16 05:00+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n" "Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
"fr/>\n" "fr/>\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 5.8.4\n" "X-Generator: Weblate 5.8.3\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
@@ -150,7 +150,7 @@ msgstr "Méthode de paiement non disponible"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15 #: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39 #: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Placed orders" msgid "Placed orders"
msgstr "Commandes réalisées" msgstr "Commandes placées"
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15 #: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39 #: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
@@ -643,40 +643,40 @@ msgstr ""
"Votre choix de couleur n'a pas un bon contraste avec du texte sur un fond " "Votre choix de couleur n'a pas un bon contraste avec du texte sur un fond "
"blanc, SVP choisissez un ton plus sombre." "blanc, SVP choisissez un ton plus sombre."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Requête de recherche" msgstr "Requête de recherche"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Tous" msgstr "Tous"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Aucun" msgstr "Aucun"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Seuls les sélectionnés" msgstr "Seuls les sélectionnés"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "Saisir le numéro de page entre 1 et %(max)s." msgstr "Saisir le numéro de page entre 1 et %(max)s."
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "Numéro de page invalide." msgstr "Numéro de page invalide."
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Utiliser un nom différent en interne" msgstr "Utiliser un nom différent en interne"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Cliquez pour fermer" msgstr "Cliquez pour fermer"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Vous avez des modifications non sauvegardées !" msgstr "Vous avez des modifications non sauvegardées !"
@@ -729,20 +729,20 @@ msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
"Veuillez indiquer le montant que l'organisateur est autorisé à retenir." "Veuillez indiquer le montant que l'organisateur est autorisé à retenir."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "SVP entrez une quantité pour un de vos types de billets." msgstr "SVP entrez une quantité pour un de vos types de billets."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "obligatoire" msgstr "obligatoire"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Fuseau horaire :" msgstr "Fuseau horaire :"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Votre heure locale:" msgstr "Votre heure locale:"
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2022-02-22 22:00+0000\n" "PO-Revision-Date: 2022-02-22 22:00+0000\n"
"Last-Translator: Ismael Menéndez Fernández <ismael.menendez@balidea.com>\n" "Last-Translator: Ismael Menéndez Fernández <ismael.menendez@balidea.com>\n"
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -658,40 +658,40 @@ msgstr ""
"A túa cor ten mal contraste para un texto con fondo branco. Por favor, " "A túa cor ten mal contraste para un texto con fondo branco. Por favor, "
"escolle un ton máis escuro." "escolle un ton máis escuro."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Consultar unha procura" msgstr "Consultar unha procura"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Todos" msgstr "Todos"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Ningún" msgstr "Ningún"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Soamente seleccionados" msgstr "Soamente seleccionados"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Usar un nome diferente internamente" msgstr "Usar un nome diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Click para cerrar" msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Tes cambios sen gardar!" msgstr "Tes cambios sen gardar!"
@@ -744,20 +744,20 @@ msgstr "Obtés %(currency)s %(price)s de volta"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Por favor, ingrese a cantidade que pode conservar o organizador." msgstr "Por favor, ingrese a cantidade que pode conservar o organizador."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Por favor, introduza un valor para cada tipo de entrada." msgstr "Por favor, introduza un valor para cada tipo de entrada."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "campo requirido" msgstr "campo requirido"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Zona horaria:" msgstr "Zona horaria:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "A súa hora local:" msgstr "A súa hora local:"
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2021-09-24 13:54+0000\n" "PO-Revision-Date: 2021-09-24 13:54+0000\n"
"Last-Translator: ofirtro <ofir.tro@gmail.com>\n" "Last-Translator: ofirtro <ofir.tro@gmail.com>\n"
"Language-Team: Hebrew <https://translate.pretix.eu/projects/pretix/pretix-js/" "Language-Team: Hebrew <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -630,40 +630,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -717,20 +717,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -7,11 +7,11 @@ 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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-11-17 00:00+0000\n" "PO-Revision-Date: 2024-11-17 00:00+0000\n"
"Last-Translator: Pavle Ergović <pavleergovic@gmail.com>\n" "Last-Translator: Pavle Ergović <pavleergovic@gmail.com>\n"
"Language-Team: Croatian <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Croatian <https://translate.pretix.eu/projects/pretix/"
"js/hr/>\n" "pretix-js/hr/>\n"
"Language: hr\n" "Language: hr\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -624,40 +624,40 @@ msgid ""
"darker shade." "darker shade."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "" msgstr ""
@@ -707,20 +707,20 @@ msgstr ""
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -7,11 +7,11 @@ 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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2024-11-28 06:00+0000\n" "PO-Revision-Date: 2024-11-28 06:00+0000\n"
"Last-Translator: Patrick Chilton <chpatrick@gmail.com>\n" "Last-Translator: Patrick Chilton <chpatrick@gmail.com>\n"
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/"
"js/hu/>\n" "pretix-js/hu/>\n"
"Language: hu\n" "Language: hu\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -671,40 +671,40 @@ msgstr ""
"A választott színek kontrasztja elégtelen, kérjük válassz sötétebb " "A választott színek kontrasztja elégtelen, kérjük válassz sötétebb "
"árnyalatot." "árnyalatot."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Összes" msgstr "Összes"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Semmi" msgstr "Semmi"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Használj másik nevet" msgstr "Használj másik nevet"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Bezárásért kattints" msgstr "Bezárásért kattints"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Mentetlen változtatások!" msgstr "Mentetlen változtatások!"
@@ -766,22 +766,22 @@ msgstr "%(currency) %(price)-tól"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "" msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Adjon meg egy mennyiséget az egyik jegytípusból." msgstr "Adjon meg egy mennyiséget az egyik jegytípusból."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
#, fuzzy #, fuzzy
#| msgid "Cart expired" #| msgid "Cart expired"
msgid "required" msgid "required"
msgstr "A kosár lejárt" msgstr "A kosár lejárt"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Időzona:" msgstr "Időzona:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "" msgstr ""
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2023-09-20 14:01+0000\n" "PO-Revision-Date: 2023-09-20 14:01+0000\n"
"Last-Translator: Mahdia Aliyy <mahdlyy.k@gmail.com>\n" "Last-Translator: Mahdia Aliyy <mahdlyy.k@gmail.com>\n"
"Language-Team: Indonesian <https://translate.pretix.eu/projects/pretix/" "Language-Team: Indonesian <https://translate.pretix.eu/projects/pretix/"
@@ -657,40 +657,40 @@ msgstr ""
"Warna Anda memiliki kontras yang buruk untuk teks dengan latar belakang " "Warna Anda memiliki kontras yang buruk untuk teks dengan latar belakang "
"putih, harap pilih warna yang lebih gelap." "putih, harap pilih warna yang lebih gelap."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Permintaan pencarian" msgstr "Permintaan pencarian"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Semua" msgstr "Semua"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Tidak ada" msgstr "Tidak ada"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Hanya dipilih" msgstr "Hanya dipilih"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Gunakan nama yang berbeda secara internal" msgstr "Gunakan nama yang berbeda secara internal"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Klik untuk menutup" msgstr "Klik untuk menutup"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Anda memiliki perubahan yang belum disimpan!" msgstr "Anda memiliki perubahan yang belum disimpan!"
@@ -740,20 +740,20 @@ msgstr "Anda mendapatkan %(currency)s %(amount)s kembali"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Silakan masukkan jumlah yang dapat disimpan oleh penyelenggara." msgstr "Silakan masukkan jumlah yang dapat disimpan oleh penyelenggara."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Masukkan jumlah untuk salah satu jenis tiket." msgstr "Masukkan jumlah untuk salah satu jenis tiket."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "diperlukan" msgstr "diperlukan"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Zona waktu:" msgstr "Zona waktu:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Waktu setempat Anda:" msgstr "Waktu setempat Anda:"
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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: 2024-12-16 14:20+0000\n" "POT-Creation-Date: 2024-11-08 13:45+0000\n"
"PO-Revision-Date: 2023-05-18 01:00+0000\n" "PO-Revision-Date: 2023-05-18 01:00+0000\n"
"Last-Translator: M C <micasadmail@gmail.com>\n" "Last-Translator: M C <micasadmail@gmail.com>\n"
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-" "Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -652,40 +652,40 @@ msgid ""
msgstr "" msgstr ""
"Il colore scelto non ha un buon contrasto, per favore scegline uno più scuro." "Il colore scelto non ha un buon contrasto, per favore scegline uno più scuro."
#: pretix/static/pretixcontrol/js/ui/main.js:442 #: pretix/static/pretixcontrol/js/ui/main.js:496
#: pretix/static/pretixcontrol/js/ui/main.js:462 #: pretix/static/pretixcontrol/js/ui/main.js:516
msgid "Search query" msgid "Search query"
msgstr "Chiave di ricerca" msgstr "Chiave di ricerca"
#: pretix/static/pretixcontrol/js/ui/main.js:460 #: pretix/static/pretixcontrol/js/ui/main.js:514
msgid "All" msgid "All"
msgstr "Tutto" msgstr "Tutto"
#: pretix/static/pretixcontrol/js/ui/main.js:461 #: pretix/static/pretixcontrol/js/ui/main.js:515
msgid "None" msgid "None"
msgstr "Nessuno" msgstr "Nessuno"
#: pretix/static/pretixcontrol/js/ui/main.js:465 #: pretix/static/pretixcontrol/js/ui/main.js:519
msgid "Selected only" msgid "Selected only"
msgstr "Solo i selezionati" msgstr "Solo i selezionati"
#: pretix/static/pretixcontrol/js/ui/main.js:808 #: pretix/static/pretixcontrol/js/ui/main.js:862
msgid "Enter page number between 1 and %(max)s." msgid "Enter page number between 1 and %(max)s."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:811 #: pretix/static/pretixcontrol/js/ui/main.js:865
msgid "Invalid page number." msgid "Invalid page number."
msgstr "" msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:969 #: pretix/static/pretixcontrol/js/ui/main.js:1023
msgid "Use a different name internally" msgid "Use a different name internally"
msgstr "Utilizza un nome diverso internamente" msgstr "Utilizza un nome diverso internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:1009 #: pretix/static/pretixcontrol/js/ui/main.js:1063
msgid "Click to close" msgid "Click to close"
msgstr "Clicca per chiudere" msgstr "Clicca per chiudere"
#: pretix/static/pretixcontrol/js/ui/main.js:1084 #: pretix/static/pretixcontrol/js/ui/main.js:1138
msgid "You have unsaved changes!" msgid "You have unsaved changes!"
msgstr "Hai cambiamenti non salvati!" msgstr "Hai cambiamenti non salvati!"
@@ -737,20 +737,20 @@ msgstr "Ricevi indietro %(currency)s %(amount)s"
msgid "Please enter the amount the organizer can keep." msgid "Please enter the amount the organizer can keep."
msgstr "Inserisci l'importo che l'organizzatore può trattenere." msgstr "Inserisci l'importo che l'organizzatore può trattenere."
#: pretix/static/pretixpresale/js/ui/main.js:454 #: pretix/static/pretixpresale/js/ui/main.js:449
msgid "Please enter a quantity for one of the ticket types." msgid "Please enter a quantity for one of the ticket types."
msgstr "Inserisci la quantità per una tipologia di biglietto." msgstr "Inserisci la quantità per una tipologia di biglietto."
#: pretix/static/pretixpresale/js/ui/main.js:506 #: pretix/static/pretixpresale/js/ui/main.js:485
msgid "required" msgid "required"
msgstr "richiesta" msgstr "richiesta"
#: pretix/static/pretixpresale/js/ui/main.js:550 #: pretix/static/pretixpresale/js/ui/main.js:588
#: pretix/static/pretixpresale/js/ui/main.js:569 #: pretix/static/pretixpresale/js/ui/main.js:607
msgid "Time zone:" msgid "Time zone:"
msgstr "Fuso orario:" msgstr "Fuso orario:"
#: pretix/static/pretixpresale/js/ui/main.js:560 #: pretix/static/pretixpresale/js/ui/main.js:598
msgid "Your local time:" msgid "Your local time:"
msgstr "Ora locale:" msgstr "Ora locale:"

Some files were not shown because too many files have changed in this diff Show More