forked from CGM_Public/pretix_original
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab4ecd0b6b | |||
| 8f13c03245 | |||
| 3b664f8b76 | |||
| 92eb5e3ece | |||
| ad38a7a407 | |||
| 51bdb274bd | |||
| 8cba60dd93 | |||
| a56c6ae1e0 | |||
| 1efd952a19 | |||
| ddd0db3d98 | |||
| dde724d0be | |||
| 9f55187690 | |||
| e572bfb752 | |||
| beccdf8dad | |||
| b141ea4ed5 | |||
| 32dd125b65 | |||
| b5794780da | |||
| 835c08f1ca | |||
| a79d5fddda | |||
| beb03e07e0 | |||
| dd2e5d09f9 | |||
| 5c2456e92e | |||
| 3579a7f298 | |||
| 5dd20de745 | |||
| 5708099fc9 | |||
| 2c2e8e7d21 | |||
| 5993482f6c | |||
| c905659dfb | |||
| 196c131ac9 | |||
| a554433fad | |||
| c552dd876c | |||
| 105ae8592d | |||
| ca4540eeb7 | |||
| 381366a248 | |||
| 816a3ec994 | |||
| 88d3d12dbc | |||
| 71caa17879 | |||
| 2ecdfde756 | |||
| 1f753a57c5 | |||
| 595c042624 | |||
| 5a5a551c21 | |||
| e74793994a | |||
| f1bdd3b7af | |||
| 13c40f9bb7 | |||
| 3e15e2a887 | |||
| 7525ee853b | |||
| f02b1be659 | |||
| 20f171b790 | |||
| 22906dfa77 | |||
| 5f74e661b3 | |||
| 5b99788354 | |||
| b45d58b60e | |||
| 2a58e958b0 | |||
| e44695dfcf | |||
| 1d289088f4 | |||
| a9be6337bc | |||
| df29d4e8c4 | |||
| bf2cabf7b6 | |||
| db614d36e6 | |||
| 13452b5d8c | |||
| 6422cd7858 | |||
| 2e87cb5691 | |||
| b53ee938bf | |||
| ec3bdd4a57 | |||
| 7b607594d8 | |||
| 53f129d5d3 | |||
| a4385c8b6e | |||
| 3acae96021 | |||
| b9add5ff6f | |||
| 4ca9813a1d | |||
| 347748896d | |||
| 0f590caa18 | |||
| 18801f2d1c | |||
| e5f29bd592 | |||
| 1f904d482b | |||
| b8ad276f53 | |||
| e109c37738 | |||
| 4d597d5be3 | |||
| ae8ec42905 | |||
| e5b89e9b08 | |||
| da91f5f117 |
@@ -60,6 +60,14 @@ http {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
location /static/staticfiles.json {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
location /static/CACHE/manifest.json {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
location /static/ {
|
||||
alias /pretix/src/pretix/static.dist/;
|
||||
access_log off;
|
||||
|
||||
Vendored
+17
-14
@@ -54,6 +54,23 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="storefrontapi/index.html">
|
||||
<span class="fa fa-shopping-cart fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="storefrontapi/index.html">
|
||||
<strong>Storefront API</strong>
|
||||
</a>
|
||||
<p>
|
||||
Documentation and reference of the headless shopping API exposed by pretix for building a custom
|
||||
storefront.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="development/index.html">
|
||||
@@ -68,7 +85,6 @@
|
||||
pretix.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="plugins/index.html">
|
||||
@@ -82,19 +98,6 @@
|
||||
<p>Documentation and details on plugins that ship with pretix or are officially supported.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sectionbox">
|
||||
<div class="icon">
|
||||
<a href="contents.html">
|
||||
<span class="fa fa-list fa-fw"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text">
|
||||
<a href="contents.html">
|
||||
<strong>Table of contents</strong>
|
||||
</a>
|
||||
<p>Detailled overview of everything contained in this documentation.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<h2>Useful links</h2>
|
||||
|
||||
@@ -248,6 +248,14 @@ The following snippet is an example on how to configure a nginx proxy for pretix
|
||||
return 404;
|
||||
}
|
||||
|
||||
location /static/staticfiles.json {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
location /static/CACHE/manifest.json {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
location /static/ {
|
||||
alias /var/pretix/venv/lib/python3.11/site-packages/pretix/static.dist/;
|
||||
access_log off;
|
||||
|
||||
@@ -156,6 +156,8 @@ Field specific input errors include the name of the offending fields as keys in
|
||||
|
||||
If you see errors of type ``429 Too Many Requests``, you should read our documentation on :ref:`rest-ratelimit`.
|
||||
|
||||
.. _`rest-types`:
|
||||
|
||||
Data types
|
||||
----------
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ lines list of objects The actual invo
|
||||
├ gross_value money (string) Price including taxes
|
||||
├ tax_value money (string) Tax amount included
|
||||
├ 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
|
||||
foreign_currency_display string If the invoice should also show the total and tax
|
||||
amount in a different currency, this contains the
|
||||
@@ -126,6 +127,10 @@ internal_reference string Customer's refe
|
||||
|
||||
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
|
||||
--------------------
|
||||
@@ -203,6 +208,7 @@ List of all invoices
|
||||
"gross_value": "23.00",
|
||||
"tax_value": "0.00",
|
||||
"tax_name": "VAT",
|
||||
"tax_code": "S/standard",
|
||||
"tax_rate": "0.00"
|
||||
}
|
||||
],
|
||||
@@ -342,6 +348,7 @@ Fetching individual invoices
|
||||
"gross_value": "23.00",
|
||||
"tax_value": "0.00",
|
||||
"tax_name": "VAT",
|
||||
"tax_code": "S/standard",
|
||||
"tax_rate": "0.00"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -84,6 +84,7 @@ fees list of objects List of fees in
|
||||
├ tax_rate decimal (string) VAT rate applied for this fee
|
||||
├ tax_value money (string) VAT included in this fee
|
||||
├ 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.
|
||||
downloads list of objects List of ticket download options for order-wise ticket
|
||||
downloading. This might be a multi-page PDF or a ZIP
|
||||
@@ -159,6 +160,10 @@ cancellation_date datetime Time of order c
|
||||
|
||||
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
|
||||
@@ -195,6 +200,7 @@ voucher_budget_use money (string) Amount of money
|
||||
are changed *after* the order was created. Can be ``null``.
|
||||
tax_rate decimal (string) VAT rate applied for 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``)
|
||||
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``)
|
||||
@@ -255,6 +261,10 @@ pdf_data object Data object req
|
||||
|
||||
The attribute ``print_logs`` has been added.
|
||||
|
||||
.. versionchanged:: 2025.1
|
||||
|
||||
The ``tax_code`` attribute has been added.
|
||||
|
||||
.. _order-payment-resource:
|
||||
|
||||
Order payment resource
|
||||
@@ -406,6 +416,7 @@ List of all orders
|
||||
"tax_rate": "0.00",
|
||||
"tax_value": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_code": null,
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
@@ -645,6 +656,7 @@ Fetching individual orders
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"tax_code": null,
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
@@ -843,7 +855,7 @@ Generating new secrets
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/regenerate_secrets/
|
||||
|
||||
Triggers generation of new ``secret`` attributes for both the order and all order positions.
|
||||
Triggers generation of new ``secret`` and ``ẁeb_secret`` attributes for both the order and all order positions.
|
||||
|
||||
**Example request**:
|
||||
|
||||
@@ -874,7 +886,7 @@ Generating new secrets
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/regenerate_secrets/
|
||||
|
||||
Triggers generation of a new ``secret`` attribute for a single order position.
|
||||
Triggers generation of a new ``secret`` and ``web_secret`` attribute for a single order position.
|
||||
|
||||
**Example request**:
|
||||
|
||||
@@ -1613,6 +1625,7 @@ List of all order positions
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"tax_code": null,
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"discount": null,
|
||||
"pseudonymization_id": "MQLJvANO3B",
|
||||
@@ -1739,6 +1752,7 @@ Fetching individual positions
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": null,
|
||||
"tax_value": "0.00",
|
||||
"tax_code": null,
|
||||
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
||||
"addon_to": null,
|
||||
"subevent": null,
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
.. spelling:word-list::
|
||||
|
||||
EN16931
|
||||
DSFinV-K
|
||||
|
||||
.. _rest-taxrules:
|
||||
|
||||
Tax rules
|
||||
@@ -18,6 +23,7 @@ id integer Internal ID of
|
||||
name multi-lingual string The tax rules' name
|
||||
internal_name string An optional name that is only used in the backend
|
||||
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
|
||||
the specified product price
|
||||
eu_reverse_charge boolean **DEPRECATED**. If ``true``, EU reverse charge rules
|
||||
@@ -42,6 +48,42 @@ custom_rules object Dynamic rules s
|
||||
|
||||
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
|
||||
---------
|
||||
|
||||
@@ -74,6 +116,7 @@ Endpoints
|
||||
"id": 1,
|
||||
"name": {"en": "VAT"},
|
||||
"internal_name": "VAT",
|
||||
"code": "S/standard",
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
@@ -115,6 +158,7 @@ Endpoints
|
||||
"id": 1,
|
||||
"name": {"en": "VAT"},
|
||||
"internal_name": "VAT",
|
||||
"code": "S/standard",
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
@@ -164,6 +208,7 @@ Endpoints
|
||||
"id": 1,
|
||||
"name": {"en": "VAT"},
|
||||
"internal_name": "VAT",
|
||||
"code": "S/standard",
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
@@ -212,6 +257,7 @@ Endpoints
|
||||
"id": 1,
|
||||
"name": {"en": "VAT"},
|
||||
"internal_name": "VAT",
|
||||
"code": "S/standard",
|
||||
"rate": "20.00",
|
||||
"price_includes_tax": true,
|
||||
"eu_reverse_charge": false,
|
||||
@@ -258,3 +304,4 @@ 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.
|
||||
|
||||
.. _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
|
||||
@@ -7,6 +7,7 @@ Table of contents
|
||||
user/index
|
||||
admin/index
|
||||
api/index
|
||||
storefrontapi/index
|
||||
development/index
|
||||
plugins/index
|
||||
license/faq
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
Basic concepts
|
||||
==============
|
||||
|
||||
This page describes basic concepts and definition that you need to know to interact
|
||||
with our Storefront API, such as authentication, pagination and similar definitions.
|
||||
|
||||
.. _`storefront-auth`:
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
||||
The storefront API requires authentication with an API key. You receive two kinds of API keys for the storefront API:
|
||||
Publishable keys and private keys. Publishable keys should be used when your website directly connects to the API.
|
||||
Private keys should be used only on server-to-server connections.
|
||||
|
||||
Localization
|
||||
------------
|
||||
|
||||
The storefront API will return localized and translated strings in many cases if you set an ``Accept-Language`` header.
|
||||
The selected locale will only be respected if it is active for the organizer or event in question.
|
||||
|
||||
.. _`storefront-compat`:
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
.. note::
|
||||
|
||||
The storefront API is currently considered experimental and may change without notice.
|
||||
Once we declare the API stable, the following compatibility policy will apply.
|
||||
|
||||
We try to avoid any breaking changes to our API to avoid hassle on your end. If possible, we'll
|
||||
build new features in a way that keeps all pre-existing API usage unchanged. In some cases,
|
||||
this might not be possible or only possible with restrictions. In these case, any
|
||||
backwards-incompatible changes will be prominently noted in the "Changes to the REST API"
|
||||
section of our release notes. If possible, we will announce them multiple releases in advance.
|
||||
|
||||
We treat the following types of changes as *backwards-compatible* so we ask you to make sure
|
||||
that your clients can deal with them properly:
|
||||
|
||||
* Support of new API endpoints
|
||||
* Support of new HTTP methods for a given API endpoint
|
||||
* Support of new query parameters for a given API endpoint
|
||||
* New fields contained in API responses
|
||||
* New possible values of enumeration-like fields
|
||||
* Response body structure or message texts on failed requests (``4xx``, ``5xx`` response codes)
|
||||
|
||||
We treat the following types of changes as *backwards-incompatible*:
|
||||
|
||||
* Type changes of fields in API responses
|
||||
* New required input fields for an API endpoint
|
||||
* New required type for input fields of an API endpoint
|
||||
* Removal of endpoints, API methods or fields
|
||||
|
||||
Pagination
|
||||
----------
|
||||
|
||||
Most lists of objects returned by pretix' API will be paginated. The response will take
|
||||
the form of:
|
||||
|
||||
.. sourcecode:: javascript
|
||||
|
||||
{
|
||||
"count": 117,
|
||||
"next": "https://pretix.eu/api/v1/organizers/?page=2",
|
||||
"previous": null,
|
||||
"results": […],
|
||||
}
|
||||
|
||||
As you can see, the response contains the total number of results in the field ``count``.
|
||||
The fields ``next`` and ``previous`` contain links to the next and previous page of results,
|
||||
respectively, or ``null`` if there is no such page. You can use those URLs to retrieve the
|
||||
respective page.
|
||||
|
||||
The field ``results`` contains a list of objects representing the first results. For most
|
||||
objects, every page contains 50 results. You can specify a lower pagination size using the
|
||||
``page_size`` query parameter, but no more than 50.
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
Error responses (of type 400-499) are returned in one of the following forms, depending on
|
||||
the type of error. General errors look like:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 405 Method Not Allowed
|
||||
Content-Type: application/json
|
||||
Content-Length: 42
|
||||
|
||||
{"detail": "Method 'DELETE' not allowed."}
|
||||
|
||||
Field specific input errors include the name of the offending fields as keys in the response:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}
|
||||
|
||||
If you see errors of type ``429 Too Many Requests``, you should read our documentation on :ref:`rest-ratelimit`.
|
||||
|
||||
Time Machine
|
||||
------------
|
||||
|
||||
Just like our shop frontend, the API allows simulating responses at a different point in time using the
|
||||
``X-Storefront-Time-Machine-Date`` header. This mechanism only works when the shop is in test mode.
|
||||
|
||||
Data types
|
||||
----------
|
||||
|
||||
See :ref:`data types <rest-types>` of the REST API.
|
||||
@@ -0,0 +1,17 @@
|
||||
.. _`storefront-api`:
|
||||
|
||||
Storefront API
|
||||
==============
|
||||
|
||||
This part of the documentation contains information about the headless e-commerce
|
||||
API exposed by pretix that can be used to build a custom checkout experience.
|
||||
|
||||
.. note::
|
||||
|
||||
The storefront API is currently considered experimental and may change without notice.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
fundamentals
|
||||
reference/index
|
||||
@@ -0,0 +1,7 @@
|
||||
API Reference
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
foo
|
||||
+4
-4
@@ -32,7 +32,7 @@ dependencies = [
|
||||
"bleach==6.2.*",
|
||||
"celery==5.4.*",
|
||||
"chardet==5.2.*",
|
||||
"cryptography>=3.4.2",
|
||||
"cryptography>=44.0.0",
|
||||
"css-inline==0.14.*",
|
||||
"defusedcsv>=1.1.0",
|
||||
"Django[argon2]==4.2.*,>=4.2.15",
|
||||
@@ -44,7 +44,7 @@ dependencies = [
|
||||
"django-formtools==2.5.1",
|
||||
"django-hierarkey==1.2.*",
|
||||
"django-hijack==3.7.*",
|
||||
"django-i18nfield==1.9.*,>=1.9.5",
|
||||
"django-i18nfield==1.10.*",
|
||||
"django-libsass==0.9",
|
||||
"django-localflavor==4.0",
|
||||
"django-markup",
|
||||
@@ -74,7 +74,7 @@ dependencies = [
|
||||
"paypal-checkout-serversdk==1.0.*",
|
||||
"PyJWT==2.9.*",
|
||||
"phonenumberslite==8.13.*",
|
||||
"Pillow==11.0.*",
|
||||
"Pillow==11.1.*",
|
||||
"pretix-plugin-build",
|
||||
"protobuf==5.29.*",
|
||||
"psycopg2-binary",
|
||||
@@ -100,7 +100,7 @@ dependencies = [
|
||||
"ua-parser==1.0.*",
|
||||
"vat_moss_forked==2020.3.20.0.11.0",
|
||||
"vobject==0.9.*",
|
||||
"webauthn==2.3.*",
|
||||
"webauthn==2.4.*",
|
||||
"zeep==4.3.*"
|
||||
]
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ from pathlib import Path
|
||||
|
||||
import setuptools
|
||||
|
||||
|
||||
sys.path.append(str(Path.cwd() / 'src'))
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ INSTALLED_APPS = [
|
||||
'pretix.presale',
|
||||
'pretix.multidomain',
|
||||
'pretix.api',
|
||||
'pretix.storefrontapi',
|
||||
'pretix.helpers',
|
||||
'rest_framework',
|
||||
'djangoformsetjs',
|
||||
|
||||
@@ -103,7 +103,7 @@ class SalesChannelMigrationMixin:
|
||||
]
|
||||
})
|
||||
|
||||
if data["sales_channels"] == all_channels:
|
||||
if set(data["sales_channels"]) == all_channels:
|
||||
data["all_sales_channels"] = True
|
||||
data["limit_sales_channels"] = []
|
||||
else:
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import PermissionDenied, ValidationError
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.functional import cached_property
|
||||
@@ -43,6 +43,7 @@ from django.utils.translation import gettext as _
|
||||
from django_countries.serializers import CountryFieldMixin
|
||||
from pytz import common_timezones
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import ChoiceField, Field
|
||||
from rest_framework.relations import SlugRelatedField
|
||||
|
||||
@@ -436,7 +437,8 @@ class CloneEventSerializer(EventSerializer):
|
||||
testmode = validated_data.pop('testmode', None)
|
||||
has_subevents = validated_data.pop('has_subevents', None)
|
||||
tz = validated_data.pop('timezone', None)
|
||||
sales_channels = validated_data.pop('sales_channels', None)
|
||||
all_sales_channels = validated_data.pop('all_sales_channels', None)
|
||||
limit_sales_channels = validated_data.pop('limit_sales_channels', None)
|
||||
date_admission = validated_data.pop('date_admission', None)
|
||||
new_event = super().create({**validated_data, 'plugins': None})
|
||||
|
||||
@@ -449,8 +451,9 @@ class CloneEventSerializer(EventSerializer):
|
||||
new_event.is_public = is_public
|
||||
if testmode is not None:
|
||||
new_event.testmode = testmode
|
||||
if sales_channels is not None:
|
||||
new_event.sales_channels = sales_channels
|
||||
if all_sales_channels is not None or limit_sales_channels is not None:
|
||||
new_event.all_sales_channels = all_sales_channels
|
||||
new_event.limit_sales_channels.set(limit_sales_channels)
|
||||
if has_subevents is not None:
|
||||
new_event.has_subevents = has_subevents
|
||||
if has_subevents is not None:
|
||||
@@ -678,8 +681,8 @@ class TaxRuleSerializer(CountryFieldMixin, I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = TaxRule
|
||||
fields = ('id', 'name', 'rate', 'price_includes_tax', 'eu_reverse_charge', 'home_country', 'internal_name',
|
||||
'keep_gross_if_rate_changes', 'custom_rules')
|
||||
fields = ('id', 'name', 'rate', 'code', 'price_includes_tax', 'eu_reverse_charge', 'home_country',
|
||||
'internal_name', 'keep_gross_if_rate_changes', 'custom_rules')
|
||||
|
||||
|
||||
class EventSettingsSerializer(SettingsSerializer):
|
||||
|
||||
@@ -512,11 +512,12 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
'company', 'street', 'zipcode', 'city', 'country', 'state', 'discount',
|
||||
'attendee_email', 'voucher', 'tax_rate', 'tax_value', 'secret', 'addon_to', 'subevent', 'checkins',
|
||||
'print_logs', 'downloads', 'answers', 'tax_rule', 'pseudonymization_id', 'pdf_data', 'seat', 'canceled',
|
||||
'valid_from', 'valid_until', 'blocked', 'voucher_budget_use')
|
||||
'print_logs', 'downloads', 'answers', 'tax_rule', 'tax_code', 'pseudonymization_id', 'pdf_data', 'seat',
|
||||
'canceled', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use')
|
||||
read_only_fields = (
|
||||
'id', 'order', 'positionid', 'item', 'variation', 'price', 'voucher', 'tax_rate', 'tax_value', 'secret',
|
||||
'addon_to', 'subevent', 'checkins', 'downloads', 'answers', 'tax_rule', 'pseudonymization_id', 'pdf_data',
|
||||
'seat', 'canceled', 'discount', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use'
|
||||
'addon_to', 'subevent', 'checkins', 'downloads', 'answers', 'tax_rule', 'tax_code', 'pseudonymization_id',
|
||||
'pdf_data', 'seat', 'canceled', 'discount', 'valid_from', 'valid_until', 'blocked', 'voucher_budget_use'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -642,7 +643,8 @@ class OrderPaymentDateField(serializers.DateField):
|
||||
class OrderFeeSerializer(I18nAwareModelSerializer):
|
||||
class Meta:
|
||||
model = OrderFee
|
||||
fields = ('id', 'fee_type', 'value', 'description', 'internal_type', 'tax_rate', 'tax_value', 'tax_rule', 'canceled')
|
||||
fields = ('id', 'fee_type', 'value', 'description', 'internal_type', 'tax_rate', 'tax_value', 'tax_rule',
|
||||
'tax_code', 'canceled')
|
||||
|
||||
|
||||
class PaymentURLField(serializers.URLField):
|
||||
@@ -1676,7 +1678,7 @@ class InlineInvoiceLineSerializer(I18nAwareModelSerializer):
|
||||
class Meta:
|
||||
model = InvoiceLine
|
||||
fields = ('position', 'description', 'item', 'variation', 'subevent', 'attendee_name', 'event_date_from',
|
||||
'event_date_to', 'gross_value', 'tax_value', 'tax_rate', 'tax_name', 'fee_type',
|
||||
'event_date_to', 'gross_value', 'tax_value', 'tax_rate', 'tax_code', 'tax_name', 'fee_type',
|
||||
'fee_internal_type', 'event_location')
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ from django.db.models import (
|
||||
from django.db.models.functions import Coalesce, Concat
|
||||
from django.http import FileResponse, HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import formats
|
||||
from django.utils.timezone import make_aware, now
|
||||
from django.utils.translation import gettext as _
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
@@ -67,6 +68,7 @@ from pretix.api.serializers.orderchange import (
|
||||
OrderPositionInfoPatchSerializer,
|
||||
)
|
||||
from pretix.api.views import RichOrderingFilter
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import (
|
||||
CachedCombinedTicket, CachedTicket, Checkin, Device, EventMetaValue,
|
||||
@@ -97,7 +99,6 @@ from pretix.base.services.tickets import generate
|
||||
from pretix.base.signals import (
|
||||
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.helpers import OF_SELF
|
||||
|
||||
@@ -646,6 +647,8 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
|
||||
order = self.get_object()
|
||||
order.secret = generate_secret()
|
||||
for op in order.all_positions.all():
|
||||
op.web_secret = generate_secret()
|
||||
op.save(update_fields=["web_secret"])
|
||||
assign_ticket_secret(
|
||||
request.event, op, force_invalidate=True, save=True
|
||||
)
|
||||
@@ -1228,9 +1231,10 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
||||
price = get_price(**kwargs)
|
||||
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):
|
||||
gross_formatted = formats.localize_input(round_decimal(price.gross, self.request.event.currency))
|
||||
return Response({
|
||||
'gross': price.gross,
|
||||
'gross_formatted': money_filter(price.gross, self.request.event.currency, hide_currency=True),
|
||||
'gross_formatted': gross_formatted,
|
||||
'net': price.net,
|
||||
'rate': price.rate,
|
||||
'name': str(price.name),
|
||||
|
||||
@@ -100,7 +100,7 @@ class MarkdownTextarea(forms.Textarea):
|
||||
|
||||
|
||||
class I18nMarkdownTextarea(i18nfield.forms.I18nTextarea):
|
||||
def format_output(self, rendered_widgets) -> str:
|
||||
def format_output(self, rendered_widgets, id_) -> str:
|
||||
rendered_widgets = rendered_widgets + [
|
||||
'<div class="i18n-field-markdown-note">%s</div>' % (
|
||||
_("You can use {markup_name} in this field.").format(
|
||||
@@ -108,11 +108,11 @@ class I18nMarkdownTextarea(i18nfield.forms.I18nTextarea):
|
||||
)
|
||||
)
|
||||
]
|
||||
return super().format_output(rendered_widgets)
|
||||
return super().format_output(rendered_widgets, id_)
|
||||
|
||||
|
||||
class I18nMarkdownTextInput(i18nfield.forms.I18nTextInput):
|
||||
def format_output(self, rendered_widgets) -> str:
|
||||
def format_output(self, rendered_widgets, id_) -> str:
|
||||
rendered_widgets = rendered_widgets + [
|
||||
'<div class="i18n-field-markdown-note">%s</div>' % (
|
||||
_("You can use {markup_name} in this field.").format(
|
||||
@@ -120,7 +120,7 @@ class I18nMarkdownTextInput(i18nfield.forms.I18nTextInput):
|
||||
)
|
||||
)
|
||||
]
|
||||
return super().format_output(rendered_widgets)
|
||||
return super().format_output(rendered_widgets, id_)
|
||||
|
||||
|
||||
SECRET_REDACTED = '*****'
|
||||
|
||||
@@ -277,6 +277,10 @@ class NamePartsFormField(forms.MultiValueField):
|
||||
return value
|
||||
|
||||
|
||||
def name_parts_is_empty(name_parts_dict):
|
||||
return not any(k != "_scheme" and v for k, v in name_parts_dict.items())
|
||||
|
||||
|
||||
class WrappedPhonePrefixSelect(Select):
|
||||
initial = None
|
||||
|
||||
@@ -1031,6 +1035,18 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
'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):
|
||||
self.event = event = kwargs.pop('event')
|
||||
self.request = kwargs.pop('request', None)
|
||||
@@ -1042,7 +1058,11 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
kwargs['initial']['country'] = guess_country_from_request(self.request, self.event)
|
||||
|
||||
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']
|
||||
elif self.validate_vat_id:
|
||||
self.fields['vat_id'].help_text = '<br/>'.join([
|
||||
@@ -1096,13 +1116,13 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
self.data = self.data.copy()
|
||||
del self.data[fprefix + 'vat_id']
|
||||
|
||||
if not event.settings.invoice_address_required or self.all_optional:
|
||||
if not self.address_required or self.all_optional:
|
||||
for k, f in self.fields.items():
|
||||
f.required = False
|
||||
f.widget.is_required = False
|
||||
if 'required' in f.widget.attrs:
|
||||
del f.widget.attrs['required']
|
||||
elif event.settings.invoice_address_company_required and not self.all_optional:
|
||||
elif self.company_required and not self.all_optional:
|
||||
self.initial['is_business'] = True
|
||||
|
||||
self.fields['is_business'].widget = BusinessBooleanRadio(require_business=True)
|
||||
@@ -1119,11 +1139,11 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
label=_('Name'),
|
||||
initial=self.instance.name_parts,
|
||||
)
|
||||
if event.settings.invoice_address_required and not event.settings.invoice_address_company_required and not self.all_optional:
|
||||
if self.address_required and not self.company_required and not self.all_optional:
|
||||
if not event.settings.invoice_name_required:
|
||||
self.fields['name_parts'].widget.attrs['data-required-if'] = '#id_is_business_0'
|
||||
self.fields['name_parts'].widget.attrs['data-required-if'] = f'#id_{self.add_prefix("is_business")}_0'
|
||||
self.fields['name_parts'].widget.attrs['data-no-required-attr'] = '1'
|
||||
self.fields['company'].widget.attrs['data-required-if'] = '#id_is_business_1'
|
||||
self.fields['company'].widget.attrs['data-required-if'] = f'#id_{self.add_prefix("is_business")}_1'
|
||||
|
||||
if not event.settings.invoice_address_beneficiary:
|
||||
del self.fields['beneficiary']
|
||||
@@ -1149,12 +1169,12 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
data['vat_id'] = ''
|
||||
if data.get('is_business') and not ask_for_vat_id(data.get('country')):
|
||||
data['vat_id'] = ''
|
||||
if self.event.settings.invoice_address_required:
|
||||
if self.address_validation and self.address_required and not self.all_optional:
|
||||
if data.get('is_business') and not data.get('company'):
|
||||
raise ValidationError({"company": _('You need to provide a company name.')})
|
||||
if not data.get('is_business') and not data.get('name_parts'):
|
||||
if not data.get('is_business') and name_parts_is_empty(data.get('name_parts', {})):
|
||||
raise ValidationError(_('You need to provide your name.'))
|
||||
if not self.all_optional and 'street' in self.fields and not data.get('street') and not data.get('zipcode') and not data.get('city'):
|
||||
if not data.get('street') and not data.get('zipcode') and not data.get('city'):
|
||||
raise ValidationError({"street": _('This field is required.')})
|
||||
|
||||
if 'vat_id' in self.changed_data or not data.get('vat_id'):
|
||||
@@ -1167,7 +1187,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
|
||||
if all(
|
||||
not v for k, v in data.items() if k not in ('is_business', 'country', 'name_parts')
|
||||
) and len(data.get('name_parts', {})) == 1:
|
||||
) and name_parts_is_empty(data.get('name_parts', {})):
|
||||
# Do not save the country if it is the only field set -- we don't know the user even checked it!
|
||||
self.cleaned_data['country'] = ''
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# 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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,62 @@
|
||||
# Generated by Django 4.2.17 on 2025-01-01 20:25
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pretixbase", "0274_tax_codes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CheckoutSession",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("cart_id", models.CharField(max_length=255, unique=True)),
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("testmode", models.BooleanField(default=False)),
|
||||
("session_data", models.JSONField(default=dict)),
|
||||
(
|
||||
"customer",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="checkout_sessions",
|
||||
to="pretixbase.customer",
|
||||
),
|
||||
),
|
||||
(
|
||||
"event",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="pretixbase.event",
|
||||
),
|
||||
),
|
||||
(
|
||||
"sales_channel",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="pretixbase.saleschannel",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="invoiceaddress",
|
||||
name="checkout_session",
|
||||
field=models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="invoice_address",
|
||||
to="pretixbase.checkoutsession",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -441,6 +441,7 @@ class Price(DecimalColumnMixin, ImportColumn):
|
||||
position.price = p.gross
|
||||
position.tax_rule = position.item.tax_rule
|
||||
position.tax_rate = p.rate
|
||||
position.tax_code = p.code
|
||||
position.tax_value = p.tax
|
||||
|
||||
|
||||
@@ -584,7 +585,7 @@ class SeatColumn(ImportColumn):
|
||||
raise ValidationError(_('Multiple matching seats were found.'))
|
||||
except Seat.DoesNotExist:
|
||||
raise ValidationError(_('No matching seat was found.'))
|
||||
if not value.is_available() or value in self._cached:
|
||||
if not value.is_available(sales_channel=previous_values.get('sales_channel')) or value in self._cached:
|
||||
raise ValidationError(
|
||||
_('The seat you selected has already been taken. Please select a different seat.'))
|
||||
self._cached.add(value)
|
||||
@@ -753,11 +754,11 @@ def get_order_import_columns(event):
|
||||
AttendeeState(event),
|
||||
Price(event),
|
||||
Secret(event),
|
||||
Saleschannel(event),
|
||||
SeatColumn(event),
|
||||
ValidFrom(event),
|
||||
ValidUntil(event),
|
||||
Locale(event),
|
||||
Saleschannel(event),
|
||||
CheckinAttentionColumn(event),
|
||||
CheckinTextColumn(event),
|
||||
Expires(event),
|
||||
|
||||
@@ -362,6 +362,7 @@ class InvoiceLine(models.Model):
|
||||
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_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)
|
||||
event_date_from = models.DateTimeField(null=True)
|
||||
event_date_to = models.DateTimeField(null=True)
|
||||
|
||||
@@ -837,7 +837,7 @@ class Item(LoggedModel):
|
||||
|
||||
if not self.tax_rule:
|
||||
t = TaxedPrice(gross=price - bundled_sum, net=price - bundled_sum, tax=Decimal('0.00'),
|
||||
rate=Decimal('0.00'), name='')
|
||||
rate=Decimal('0.00'), name='', code=None)
|
||||
else:
|
||||
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,
|
||||
@@ -845,6 +845,7 @@ class Item(LoggedModel):
|
||||
|
||||
if bundled_sum:
|
||||
t.name = "MIXED!"
|
||||
t.code = None
|
||||
t.gross += bundled_sum
|
||||
t.net += bundled_sum_net
|
||||
t.tax += bundled_sum_tax
|
||||
@@ -1258,7 +1259,7 @@ class ItemVariation(models.Model):
|
||||
|
||||
if not self.item.tax_rule:
|
||||
t = TaxedPrice(gross=price, net=price, tax=Decimal('0.00'),
|
||||
rate=Decimal('0.00'), name='')
|
||||
rate=Decimal('0.00'), name='', code=None)
|
||||
else:
|
||||
t = self.item.tax_rule.tax(price, base_price_is=base_price_is, currency=currency,
|
||||
override_tax_rate=override_tax_rate,
|
||||
@@ -1280,6 +1281,7 @@ class ItemVariation(models.Model):
|
||||
t.net += bprice.net - compare_price.net
|
||||
t.tax += bprice.tax - compare_price.tax
|
||||
t.name = "MIXED!"
|
||||
t.code = None
|
||||
|
||||
return t
|
||||
|
||||
|
||||
@@ -55,16 +55,17 @@ from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, transaction
|
||||
from django.db.models import (
|
||||
Case, Exists, F, Max, OuterRef, Q, Subquery, Sum, Value, When,
|
||||
Case, Exists, F, Max, OuterRef, Prefetch, Q, Subquery, Sum, Value, When,
|
||||
)
|
||||
from django.db.models.functions import Coalesce, Greatest
|
||||
from django.db.models.signals import post_delete
|
||||
from django.dispatch import receiver
|
||||
from django.urls import reverse
|
||||
from django.utils.crypto import get_random_string, salted_hmac
|
||||
from django.utils.encoding import escape_uri_path
|
||||
from django.utils.encoding import escape_uri_path, force_str
|
||||
from django.utils.formats import date_format
|
||||
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.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django_countries.fields import Country
|
||||
@@ -1256,7 +1257,7 @@ class Order(LockModel, LoggedModel):
|
||||
keys = set(target_transaction_count.keys()) | set(current_transaction_count.keys())
|
||||
create = []
|
||||
for k in keys:
|
||||
positionid, itemid, variationid, subeventid, price, taxrate, taxruleid, taxvalue, feetype, internaltype = k
|
||||
positionid, itemid, variationid, subeventid, price, taxrate, taxruleid, taxvalue, feetype, internaltype, taxcode = k
|
||||
d = target_transaction_count[k] - current_transaction_count[k]
|
||||
if d:
|
||||
create.append(Transaction(
|
||||
@@ -1272,6 +1273,7 @@ class Order(LockModel, LoggedModel):
|
||||
tax_rate=taxrate,
|
||||
tax_rule_id=taxruleid,
|
||||
tax_value=taxvalue,
|
||||
tax_code=taxcode,
|
||||
fee_type=feetype,
|
||||
internal_type=internaltype,
|
||||
))
|
||||
@@ -2313,6 +2315,10 @@ class OrderFee(models.Model):
|
||||
on_delete=models.PROTECT,
|
||||
null=True, blank=True
|
||||
)
|
||||
tax_code = models.CharField(
|
||||
max_length=190,
|
||||
null=True, blank=True,
|
||||
)
|
||||
tax_value = models.DecimalField(
|
||||
max_digits=13, decimal_places=2,
|
||||
verbose_name=_('Tax value')
|
||||
@@ -2340,6 +2346,16 @@ class OrderFee(models.Model):
|
||||
self._transaction_key_reset()
|
||||
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):
|
||||
self.__initial_transaction_key = Transaction.key(self)
|
||||
self.__initial_canceled = self.canceled
|
||||
@@ -2370,9 +2386,11 @@ class OrderFee(models.Model):
|
||||
if self.tax_rule:
|
||||
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_code = tax.code
|
||||
self.tax_value = tax.tax
|
||||
else:
|
||||
self.tax_value = Decimal('0.00')
|
||||
self.tax_code = None
|
||||
self.tax_rate = Decimal('0.00')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
@@ -2381,6 +2399,7 @@ class OrderFee(models.Model):
|
||||
|
||||
if self.tax_rate is None:
|
||||
self._calculate_tax()
|
||||
|
||||
self.order.touch()
|
||||
|
||||
if not self.get_deferred_fields():
|
||||
@@ -2468,6 +2487,10 @@ class OrderPosition(AbstractPosition):
|
||||
on_delete=models.PROTECT,
|
||||
null=True, blank=True
|
||||
)
|
||||
tax_code = models.CharField(
|
||||
max_length=190,
|
||||
null=True, blank=True,
|
||||
)
|
||||
tax_value = models.DecimalField(
|
||||
max_digits=13, decimal_places=2,
|
||||
verbose_name=_('Tax value')
|
||||
@@ -2525,6 +2548,16 @@ class OrderPosition(AbstractPosition):
|
||||
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
|
||||
def sort_key(self):
|
||||
return self.addon_to.positionid if self.addon_to else self.positionid, self.addon_to_id or 0, self.positionid
|
||||
@@ -2697,11 +2730,13 @@ class OrderPosition(AbstractPosition):
|
||||
if self.tax_rule:
|
||||
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_code = tax.code
|
||||
self.tax_value = tax.tax
|
||||
if tax.gross != self.price:
|
||||
raise ValueError('Invalid tax calculation')
|
||||
else:
|
||||
self.tax_value = Decimal('0.00')
|
||||
self.tax_code = None
|
||||
self.tax_rate = Decimal('0.00')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
@@ -2972,6 +3007,10 @@ class Transaction(models.Model):
|
||||
on_delete=models.PROTECT,
|
||||
null=True, blank=True
|
||||
)
|
||||
tax_code = models.CharField(
|
||||
max_length=190,
|
||||
null=True, blank=True,
|
||||
)
|
||||
tax_value = models.DecimalField(
|
||||
max_digits=13, decimal_places=2,
|
||||
verbose_name=_('Tax value')
|
||||
@@ -2992,17 +3031,27 @@ class Transaction(models.Model):
|
||||
raise ValidationError('Should set either item or fee type')
|
||||
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
|
||||
def key(obj):
|
||||
if isinstance(obj, Transaction):
|
||||
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_rule_id, obj.tax_value, obj.fee_type, obj.internal_type, obj.tax_code)
|
||||
elif isinstance(obj, OrderPosition):
|
||||
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_rule_id, obj.tax_value, None, None, obj.tax_code)
|
||||
elif isinstance(obj, OrderFee):
|
||||
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_rule_id, obj.tax_value, obj.fee_type, obj.internal_type, obj.tax_code)
|
||||
raise ValueError('invalid state') # noqa
|
||||
|
||||
@property
|
||||
@@ -3014,6 +3063,64 @@ class Transaction(models.Model):
|
||||
return self.tax_value * self.count
|
||||
|
||||
|
||||
class CheckoutSession(models.Model):
|
||||
"""
|
||||
A checkout session optionally bundles cart positions with additional information. This is historically
|
||||
not required in pretix and currently only used in the Storefront API.
|
||||
"""
|
||||
event = models.ForeignKey(
|
||||
Event,
|
||||
verbose_name=_("Event"),
|
||||
related_name="checkout_sessions",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
cart_id = models.CharField(
|
||||
max_length=255, unique=True,
|
||||
verbose_name=_("Cart ID (e.g. session key)"),
|
||||
)
|
||||
created = models.DateTimeField(
|
||||
verbose_name=_("Date"),
|
||||
auto_now_add=True,
|
||||
)
|
||||
customer = models.ForeignKey(
|
||||
Customer,
|
||||
related_name='checkout_sessions',
|
||||
null=True, blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
sales_channel = models.ForeignKey(
|
||||
"SalesChannel",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
testmode = models.BooleanField(default=False)
|
||||
session_data = models.JSONField(default=dict)
|
||||
|
||||
def get_cart_positions(self, prefetch_questions=False):
|
||||
qs = CartPosition.objects.filter(event=self.event, cart_id=self.cart_id).select_related(
|
||||
"item", "variation", "subevent",
|
||||
)
|
||||
if prefetch_questions:
|
||||
qqs = self.event.questions.filter(ask_during_checkin=False, hidden=False)
|
||||
qs = qs.prefetch_related(
|
||||
Prefetch("answers",
|
||||
QuestionAnswer.objects.prefetch_related("options"),
|
||||
to_attr="answerlist"),
|
||||
Prefetch("item__questions",
|
||||
qqs.prefetch_related(
|
||||
Prefetch("options", QuestionOption.objects.prefetch_related(Prefetch(
|
||||
# This prefetch statement is utter bullshit, but it actually prevents Django from doing
|
||||
# a lot of queries since ModelChoiceIterator stops trying to be clever once we have
|
||||
# a prefetch lookup on this query...
|
||||
"question",
|
||||
Question.objects.none(),
|
||||
to_attr="dummy"
|
||||
)))
|
||||
).select_related("dependency_question"),
|
||||
to_attr="questions_to_ask")
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
class CartPosition(AbstractPosition):
|
||||
"""
|
||||
A cart position is similar to an order line, except that it is not
|
||||
@@ -3166,6 +3273,7 @@ class CartPosition(AbstractPosition):
|
||||
if line_price.gross != self.line_price_gross or line_price.rate != self.tax_rate:
|
||||
self.line_price_gross = line_price.gross
|
||||
self.tax_rate = line_price.rate
|
||||
self.tax_code = line_price.code
|
||||
self.save(update_fields=['line_price_gross', 'tax_rate'])
|
||||
|
||||
@property
|
||||
@@ -3195,6 +3303,13 @@ class CartPosition(AbstractPosition):
|
||||
|
||||
class InvoiceAddress(models.Model):
|
||||
last_modified = models.DateTimeField(auto_now=True)
|
||||
checkout_session = models.OneToOneField(
|
||||
CheckoutSession,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='invoice_address',
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
order = models.OneToOneField(Order, null=True, blank=True, related_name='invoice_address', on_delete=models.CASCADE)
|
||||
customer = models.ForeignKey(
|
||||
Customer,
|
||||
|
||||
+220
-12
@@ -21,6 +21,7 @@
|
||||
#
|
||||
import json
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
|
||||
import jsonschema
|
||||
from django.contrib.staticfiles import finders
|
||||
@@ -30,8 +31,9 @@ from django.db import models
|
||||
from django.utils.deconstruct import deconstructible
|
||||
from django.utils.formats import localize
|
||||
from django.utils.functional import lazy
|
||||
from django.utils.hashable import make_hashable
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _, pgettext
|
||||
from django.utils.translation import gettext_lazy as _, pgettext, pgettext_lazy
|
||||
from i18nfield.fields import I18nCharField
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
@@ -42,7 +44,7 @@ from pretix.helpers.countries import FastCountryField
|
||||
|
||||
|
||||
class TaxedPrice:
|
||||
def __init__(self, *, gross: Decimal, net: Decimal, tax: Decimal, rate: Decimal, name: str):
|
||||
def __init__(self, *, gross: Decimal, net: Decimal, tax: Decimal, rate: Decimal, name: str, code: Optional[str]):
|
||||
if net + tax != gross:
|
||||
raise ValueError('Net value and tax value need to add to the gross value')
|
||||
self.gross = gross
|
||||
@@ -50,6 +52,7 @@ class TaxedPrice:
|
||||
self.tax = tax
|
||||
self.rate = rate
|
||||
self.name = name
|
||||
self.code = code
|
||||
|
||||
def __repr__(self):
|
||||
return '{} + {}% = {}'.format(localize(self.net), localize(self.rate), localize(self.gross))
|
||||
@@ -72,6 +75,7 @@ class TaxedPrice:
|
||||
tax=newgross - newnet,
|
||||
rate=self.rate,
|
||||
name=self.name,
|
||||
code=self.code,
|
||||
)
|
||||
|
||||
def __mul__(self, other):
|
||||
@@ -85,6 +89,7 @@ class TaxedPrice:
|
||||
tax=newgross - newnet,
|
||||
rate=self.rate,
|
||||
name=self.name,
|
||||
code=self.code,
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
@@ -93,7 +98,8 @@ class TaxedPrice:
|
||||
self.net == other.net and
|
||||
self.tax == other.tax and
|
||||
self.rate == other.rate and
|
||||
self.name == other.name
|
||||
self.name == other.name and
|
||||
self.code == other.code
|
||||
)
|
||||
|
||||
|
||||
@@ -102,7 +108,8 @@ TAXED_ZERO = TaxedPrice(
|
||||
net=Decimal('0.00'),
|
||||
tax=Decimal('0.00'),
|
||||
rate=Decimal('0.00'),
|
||||
name=''
|
||||
name='',
|
||||
code=None,
|
||||
)
|
||||
|
||||
EU_COUNTRIES = {
|
||||
@@ -125,6 +132,152 @@ VAT_ID_COUNTRIES = EU_COUNTRIES | {'CH', 'NO'}
|
||||
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):
|
||||
cc = str(cc)
|
||||
return cc in EU_COUNTRIES
|
||||
@@ -173,6 +326,14 @@ class TaxRule(LoggedModel):
|
||||
help_text=_('Should be short, e.g. "VAT"'),
|
||||
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(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
@@ -250,6 +411,16 @@ class TaxRule(LoggedModel):
|
||||
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.'))
|
||||
|
||||
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):
|
||||
if self.price_includes_tax:
|
||||
s = _('incl. {rate}% {name}').format(rate=self.rate, name=self.name)
|
||||
@@ -276,8 +447,9 @@ class TaxRule(LoggedModel):
|
||||
return Decimal(rule.get('rate'))
|
||||
return Decimal(self.rate)
|
||||
|
||||
def tax(self, base_price, base_price_is='auto', currency=None, override_tax_rate=None, invoice_address=None,
|
||||
subtract_from_gross=Decimal('0.00'), gross_price_is_tax_rate: Decimal = None, force_fixed_gross_price=False):
|
||||
def tax(self, base_price, base_price_is='auto', currency=None, override_tax_rate=None, override_tax_code=None,
|
||||
invoice_address=None, subtract_from_gross=Decimal('0.00'), gross_price_is_tax_rate: Decimal = None,
|
||||
force_fixed_gross_price=False):
|
||||
from .event import Event
|
||||
try:
|
||||
currency = currency or self.event.currency
|
||||
@@ -285,6 +457,13 @@ class TaxRule(LoggedModel):
|
||||
pass
|
||||
|
||||
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:
|
||||
rate = override_tax_rate
|
||||
elif invoice_address:
|
||||
@@ -317,11 +496,8 @@ class TaxRule(LoggedModel):
|
||||
if rate == Decimal('0.00'):
|
||||
gross = _limit_subtract(base_price, subtract_from_gross)
|
||||
return TaxedPrice(
|
||||
net=gross,
|
||||
gross=gross,
|
||||
tax=Decimal('0.00'),
|
||||
rate=rate,
|
||||
name=self.name,
|
||||
net=gross, gross=gross, tax=Decimal('0.00'),
|
||||
rate=rate, name=self.name, code=code,
|
||||
)
|
||||
|
||||
if base_price_is == 'auto':
|
||||
@@ -346,7 +522,7 @@ class TaxRule(LoggedModel):
|
||||
|
||||
return TaxedPrice(
|
||||
net=net, gross=gross, tax=gross - net,
|
||||
rate=rate, name=self.name
|
||||
rate=rate, name=self.name, code=code,
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -427,6 +603,38 @@ class TaxRule(LoggedModel):
|
||||
return True
|
||||
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):
|
||||
if self._custom_rules:
|
||||
rule = self.get_matching_rule(invoice_address)
|
||||
|
||||
@@ -722,6 +722,10 @@ class BasePaymentProvider:
|
||||
"""
|
||||
return ""
|
||||
|
||||
def storefrontapi_prepare(self, session_data, total, info):
|
||||
# TODO: docstring
|
||||
return True
|
||||
|
||||
def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str]:
|
||||
"""
|
||||
Will be called after the user selects this provider as their payment method.
|
||||
@@ -1447,6 +1451,28 @@ class GiftCardPayment(BasePaymentProvider):
|
||||
}
|
||||
)
|
||||
|
||||
def storefrontapi_prepare(self, session_data, total, info):
|
||||
# todo: validate gift card not paid with gift card
|
||||
try:
|
||||
gc = self.event.organizer.accepted_gift_cards.get(
|
||||
secret=info.get("giftcard").strip()
|
||||
)
|
||||
try:
|
||||
self._add_giftcard_to_cart(session_data, gc)
|
||||
return True
|
||||
except ValidationError as e:
|
||||
raise PaymentException(str(e.message))
|
||||
except GiftCard.DoesNotExist:
|
||||
if self.event.vouchers.filter(code__iexact=info.get("giftcard")).exists():
|
||||
raise PaymentException(
|
||||
_("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below "
|
||||
"the product selection.")
|
||||
)
|
||||
else:
|
||||
raise PaymentException(_("This gift card is not known."))
|
||||
except GiftCard.MultipleObjectsReturned:
|
||||
raise PaymentException(_("This gift card can not be redeemed since its code is not unique. Please contact the organizer of this event."))
|
||||
|
||||
def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str, None]:
|
||||
for p in get_cart(request):
|
||||
if p.item.issue_giftcard:
|
||||
|
||||
@@ -1513,6 +1513,7 @@ def get_fees(event, request, total, invoice_address, payments, positions):
|
||||
value=payment_fee,
|
||||
tax_rate=payment_fee_tax.rate,
|
||||
tax_value=payment_fee_tax.tax,
|
||||
tax_code=payment_fee_tax.code,
|
||||
tax_rule=payment_fee_tax_rule
|
||||
))
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ from datetime import timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
from django.db.models import Exists, OuterRef
|
||||
from django.dispatch import receiver
|
||||
from django.utils.timezone import now
|
||||
from django_scopes import scopes_disabled
|
||||
@@ -32,6 +33,7 @@ from pretix.base.models.customers import CustomerSSOGrant
|
||||
|
||||
from ..models import CachedFile, CartPosition, InvoiceAddress
|
||||
from ..models.auth import UserKnownLoginSource
|
||||
from ..models.orders import CheckoutSession
|
||||
from ..signals import periodic_task
|
||||
|
||||
|
||||
@@ -42,6 +44,10 @@ def clean_cart_positions(sender, **kwargs):
|
||||
cp.delete()
|
||||
for cp in CartPosition.objects.filter(expires__lt=now() - timedelta(days=14), addon_to__isnull=True):
|
||||
cp.delete()
|
||||
for cs in CheckoutSession.objects.filter(created__lt=now() - timedelta(days=14)).exclude(
|
||||
Exists(CartPosition.objects.filter(cart_id=OuterRef("cart_id")))
|
||||
):
|
||||
cs.delete()
|
||||
for ia in InvoiceAddress.objects.filter(order__isnull=True, customer__isnull=True, last_modified__lt=now() - timedelta(days=14)):
|
||||
ia.delete()
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from typing import List
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from pretix.base.models import CartPosition, ItemCategory, SalesChannel
|
||||
from pretix.presale.views.event import get_grouped_items
|
||||
from pretix.base.storelogic.products import get_items_for_product_list
|
||||
|
||||
|
||||
class DummyCategory:
|
||||
@@ -161,7 +161,7 @@ class CrossSellingService:
|
||||
]
|
||||
|
||||
def _prepare_items(self, subevent, items_qs, discount_info):
|
||||
items, _btn = get_grouped_items(
|
||||
items, _btn = get_items_for_product_list(
|
||||
self.event,
|
||||
subevent=subevent,
|
||||
voucher=None,
|
||||
|
||||
@@ -271,7 +271,9 @@ 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_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,
|
||||
tax_rate=p.tax_rate, tax_name=p.tax_rule.name if p.tax_rule else ''
|
||||
tax_rate=p.tax_rate,
|
||||
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:
|
||||
@@ -305,6 +307,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
||||
),
|
||||
tax_value=fee.tax_value,
|
||||
tax_rate=fee.tax_rate,
|
||||
tax_code=fee.tax_code,
|
||||
tax_name=fee.tax_rule.name if fee.tax_rule else '',
|
||||
fee_type=fee.fee_type,
|
||||
fee_internal_type=fee.internal_type or None,
|
||||
@@ -491,13 +494,13 @@ def build_preview_invoice_pdf(event):
|
||||
InvoiceLine.objects.create(
|
||||
invoice=invoice, description=_("Sample product {}").format(i + 1),
|
||||
gross_value=tax.gross, tax_value=tax.tax,
|
||||
tax_rate=tax.rate, tax_name=tax.name
|
||||
tax_rate=tax.rate, tax_name=tax.name, tax_code=tax.code,
|
||||
)
|
||||
else:
|
||||
for i in range(5):
|
||||
InvoiceLine.objects.create(
|
||||
invoice=invoice, description=_("Sample product A"),
|
||||
gross_value=100, tax_value=0, tax_rate=0
|
||||
gross_value=100, tax_value=0, tax_rate=0, tax_code=None,
|
||||
)
|
||||
|
||||
return event.invoice_renderer.generate(invoice)
|
||||
|
||||
@@ -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)
|
||||
|
||||
if position.seat is not None:
|
||||
lock_seats.append(position.seat)
|
||||
lock_seats.append((order.sales_channel, position.seat))
|
||||
except (ValidationError, ImportError) as e:
|
||||
raise DataImportError(
|
||||
_('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():
|
||||
# We don't support vouchers, quotas, or memberships here, so we only need to lock if seats are in use
|
||||
if lock_seats:
|
||||
lock_objects(lock_seats, shared_lock_objects=[event])
|
||||
for s in lock_seats:
|
||||
if not s.is_available():
|
||||
lock_objects([s for c, s in lock_seats], shared_lock_objects=[event])
|
||||
for c, s in lock_seats:
|
||||
if not s.is_available(sales_channel=c):
|
||||
raise DataImportError(_('The seat you selected has already been taken. Please select a different seat.'))
|
||||
|
||||
save_transactions = []
|
||||
|
||||
@@ -1721,16 +1721,17 @@ class OrderChangeManager:
|
||||
|
||||
try:
|
||||
new_rate = tax_rule.tax_rate_for(ia)
|
||||
new_code = tax_rule.tax_code_for(ia)
|
||||
except TaxRule.SaleNotAllowed:
|
||||
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
|
||||
if new_rate != pos.tax_rate:
|
||||
if new_rate != pos.tax_rate or new_code != pos.tax_code:
|
||||
if keep == 'net':
|
||||
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_rate=new_rate, override_tax_code=new_code)
|
||||
else:
|
||||
new_tax = tax_rule.tax(pos.price, base_price_is='gross', currency=self.event.currency,
|
||||
override_tax_rate=new_rate)
|
||||
override_tax_rate=new_rate, override_tax_code=new_code)
|
||||
self._totaldiff += new_tax.gross - pos.price
|
||||
self._operations.append(self.PriceOperation(pos, new_tax, new_tax.gross - pos.price))
|
||||
self._invoice_dirty = True
|
||||
@@ -2304,6 +2305,7 @@ class OrderChangeManager:
|
||||
op.position.price = op.price.gross
|
||||
op.position.tax_rate = op.price.rate
|
||||
op.position.tax_value = op.price.tax
|
||||
op.position.tax_code = op.price.code
|
||||
op.position.save()
|
||||
elif isinstance(op, self.TaxRuleOperation):
|
||||
if isinstance(op.position, OrderPosition):
|
||||
@@ -2400,7 +2402,7 @@ class OrderChangeManager:
|
||||
elif isinstance(op, self.AddOperation):
|
||||
pos = OrderPosition.objects.create(
|
||||
item=op.item, variation=op.variation, addon_to=op.addon_to,
|
||||
price=op.price.gross, order=self.order, tax_rate=op.price.rate,
|
||||
price=op.price.gross, order=self.order, tax_rate=op.price.rate, tax_code=op.price.code,
|
||||
tax_value=op.price.tax, tax_rule=op.item.tax_rule,
|
||||
positionid=nextposid, subevent=op.subevent, seat=op.seat,
|
||||
used_membership=op.membership, valid_from=op.valid_from, valid_until=op.valid_until,
|
||||
@@ -2423,6 +2425,8 @@ class OrderChangeManager:
|
||||
elif isinstance(op, self.SplitOperation):
|
||||
split_positions.append(op.position)
|
||||
elif isinstance(op, self.RegenerateSecretOperation):
|
||||
op.position.web_secret = generate_secret()
|
||||
op.position.save(update_fields=["web_secret"])
|
||||
assign_ticket_secret(
|
||||
event=self.event, position=op.position, force_invalidate=True, save=True
|
||||
)
|
||||
@@ -2529,6 +2533,7 @@ class OrderChangeManager:
|
||||
'new_order': split_order.code,
|
||||
})
|
||||
op.order = split_order
|
||||
op.web_secret = generate_secret()
|
||||
assign_ticket_secret(
|
||||
self.event, position=op, force_invalidate=True,
|
||||
)
|
||||
|
||||
@@ -91,9 +91,11 @@ def get_price(item: Item, variation: ItemVariation = None,
|
||||
|
||||
if custom_price_is_net:
|
||||
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)
|
||||
else:
|
||||
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)
|
||||
else:
|
||||
price = tax_rule.tax(price, invoice_address=invoice_address, subtract_from_gross=bundled_sum)
|
||||
@@ -146,10 +148,12 @@ def get_line_price(price_after_voucher: Decimal, custom_price_input: Decimal, cu
|
||||
|
||||
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,
|
||||
invoice_address=invoice_address, subtract_from_gross=bundled_sum)
|
||||
override_tax_code=price.code, invoice_address=invoice_address,
|
||||
subtract_from_gross=bundled_sum)
|
||||
else:
|
||||
price = tax_rule.tax(max(custom_price_input, price.gross), base_price_is='gross', override_tax_rate=price.rate,
|
||||
invoice_address=invoice_address, subtract_from_gross=bundled_sum)
|
||||
override_tax_code=price.code, invoice_address=invoice_address,
|
||||
subtract_from_gross=bundled_sum)
|
||||
else:
|
||||
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')
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#
|
||||
import logging
|
||||
import os
|
||||
from decimal import Decimal
|
||||
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils.timezone import now
|
||||
@@ -97,9 +98,9 @@ def preview(event: int, provider: str):
|
||||
event = Event.objects.get(id=event)
|
||||
|
||||
with rolledback_transaction(), language(event.settings.locale, event.settings.region):
|
||||
item = event.items.create(name=_("Sample product"), default_price=42.23,
|
||||
item = event.items.create(name=_("Sample product"), default_price=Decimal('42.23'),
|
||||
description=_("Sample product description"))
|
||||
item2 = event.items.create(name=_("Sample workshop"), default_price=23.40)
|
||||
item2 = event.items.create(name=_("Sample workshop"), default_price=Decimal('23.40'))
|
||||
|
||||
from pretix.base.models import Order
|
||||
order = event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
class IncompleteError(Exception):
|
||||
pass
|
||||
@@ -0,0 +1,118 @@
|
||||
import copy
|
||||
from collections import defaultdict
|
||||
|
||||
from pretix.base.models.tax import TaxedPrice
|
||||
from pretix.base.storelogic.products import get_items_for_product_list
|
||||
|
||||
|
||||
def addons_is_completed(cart_positions):
|
||||
for cartpos in cart_positions.filter(addon_to__isnull=True).prefetch_related(
|
||||
'item__addons', 'item__addons__addon_category', 'addons', 'addons__item'
|
||||
):
|
||||
a = cartpos.addons.all()
|
||||
for iao in cartpos.item.addons.all():
|
||||
found = len([1 for p in a if p.item.category_id == iao.addon_category_id and not p.is_bundled])
|
||||
if found < iao.min_count or found > iao.max_count:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def addons_is_applicable(cart_positions):
|
||||
return cart_positions.filter(item__addons__isnull=False).exists()
|
||||
|
||||
|
||||
def get_addon_groups(event, sales_channel, customer, cart_positions):
|
||||
quota_cache = {}
|
||||
item_cache = {}
|
||||
groups = []
|
||||
for cartpos in sorted(cart_positions.filter(addon_to__isnull=True).prefetch_related(
|
||||
'item__addons', 'item__addons__addon_category', 'addons', 'addons__variation',
|
||||
), key=lambda c: c.sort_key):
|
||||
groupentry = {
|
||||
'pos': cartpos,
|
||||
'item': cartpos.item,
|
||||
'variation': cartpos.variation,
|
||||
'categories': []
|
||||
}
|
||||
|
||||
current_addon_products = defaultdict(list)
|
||||
for a in cartpos.addons.all():
|
||||
if not a.is_bundled:
|
||||
current_addon_products[a.item_id, a.variation_id].append(a)
|
||||
|
||||
for iao in cartpos.item.addons.all():
|
||||
ckey = '{}-{}'.format(cartpos.subevent.pk if cartpos.subevent else 0, iao.addon_category.pk)
|
||||
|
||||
if ckey not in item_cache:
|
||||
# Get all items to possibly show
|
||||
items, _btn = get_items_for_product_list(
|
||||
event,
|
||||
subevent=cartpos.subevent,
|
||||
voucher=None,
|
||||
channel=sales_channel,
|
||||
base_qs=iao.addon_category.items,
|
||||
allow_addons=True,
|
||||
quota_cache=quota_cache,
|
||||
memberships=(
|
||||
customer.usable_memberships(
|
||||
for_event=cartpos.subevent or event,
|
||||
testmode=event.testmode
|
||||
)
|
||||
if customer else None
|
||||
),
|
||||
)
|
||||
item_cache[ckey] = items
|
||||
else:
|
||||
# We can use the cache to prevent a database fetch, but we need separate Python objects
|
||||
# or our things below like setting `i.initial` will do the wrong thing.
|
||||
items = [copy.copy(i) for i in item_cache[ckey]]
|
||||
for i in items:
|
||||
i.available_variations = [copy.copy(v) for v in i.available_variations]
|
||||
|
||||
for i in items:
|
||||
i.allow_waitinglist = False
|
||||
|
||||
if i.has_variations:
|
||||
for v in i.available_variations:
|
||||
v.initial = len(current_addon_products[i.pk, v.pk])
|
||||
if v.initial and i.free_price:
|
||||
a = current_addon_products[i.pk, v.pk][0]
|
||||
v.initial_price = TaxedPrice(
|
||||
net=a.price - a.tax_value,
|
||||
gross=a.price,
|
||||
tax=a.tax_value,
|
||||
name=a.item.tax_rule.name if a.item.tax_rule else "",
|
||||
rate=a.tax_rate,
|
||||
code=a.item.tax_rule.code if a.item.tax_rule else None,
|
||||
)
|
||||
else:
|
||||
v.initial_price = v.suggested_price
|
||||
i.expand = any(v.initial for v in i.available_variations)
|
||||
else:
|
||||
i.initial = len(current_addon_products[i.pk, None])
|
||||
if i.initial and i.free_price:
|
||||
a = current_addon_products[i.pk, None][0]
|
||||
i.initial_price = TaxedPrice(
|
||||
net=a.price - a.tax_value,
|
||||
gross=a.price,
|
||||
tax=a.tax_value,
|
||||
name=a.item.tax_rule.name if a.item.tax_rule else "",
|
||||
rate=a.tax_rate,
|
||||
code=a.item.tax_rule.code if a.item.tax_rule else None,
|
||||
)
|
||||
else:
|
||||
i.initial_price = i.suggested_price
|
||||
|
||||
if items:
|
||||
groupentry['categories'].append({
|
||||
'category': iao.addon_category,
|
||||
'price_included': iao.price_included or (cartpos.voucher_id and cartpos.voucher.all_addons_included),
|
||||
'multi_allowed': iao.multi_allowed,
|
||||
'min_count': iao.min_count,
|
||||
'max_count': iao.max_count,
|
||||
'iao': iao,
|
||||
'items': items
|
||||
})
|
||||
if groupentry['categories']:
|
||||
groups.append(groupentry)
|
||||
return groups
|
||||
@@ -0,0 +1,271 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import EmailValidator
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.base.models import CartPosition, Question
|
||||
from pretix.base.services.checkin import _save_answers
|
||||
from pretix.base.storelogic import IncompleteError
|
||||
from pretix.presale.signals import question_form_fields
|
||||
|
||||
|
||||
class Field:
|
||||
@property
|
||||
def identifier(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def help_text(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def required(self):
|
||||
return True
|
||||
|
||||
@property
|
||||
def validation_hints(self):
|
||||
raise {}
|
||||
|
||||
def validate_input(self, value):
|
||||
return value
|
||||
|
||||
|
||||
class PositionField(Field):
|
||||
def save_input(self, position, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
def current_value(self, position):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class SessionField(Field):
|
||||
def save_input(self, session_data, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
def current_value(self, session_data):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class QuestionField(PositionField):
|
||||
def __init__(self, question: Question):
|
||||
self.question = question
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self.question.question
|
||||
|
||||
@property
|
||||
def help_text(self):
|
||||
return self.question.help_text
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self.question.type
|
||||
|
||||
@property
|
||||
def identifier(self):
|
||||
return f"question_{self.question.identifier}"
|
||||
|
||||
def validate_input(self, value):
|
||||
return self.question.clean_answer(value)
|
||||
|
||||
def required(self, value):
|
||||
return self.question.required
|
||||
|
||||
def validation_hints(self):
|
||||
d = {
|
||||
"valid_number_min": self.question.valid_number_min,
|
||||
"valid_number_max": self.question.valid_number_max,
|
||||
"valid_date_min": self.question.valid_date_min,
|
||||
"valid_date_max": self.question.valid_date_max,
|
||||
"valid_datetime_min": self.question.valid_datetime_min,
|
||||
"valid_datetime_max": self.question.valid_datetime_max,
|
||||
"valid_string_length_max": self.question.valid_string_length_max,
|
||||
"dependency_on": f"question_{self.question.dependency_question.identifier}" if self.question.dependency_question_id else None,
|
||||
"dependency_values": self.question.dependency_values,
|
||||
}
|
||||
if self.question.type in (Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE):
|
||||
d["choices"] = [
|
||||
{
|
||||
"identifier": opt.identifier,
|
||||
"label": str(opt.answer)
|
||||
}
|
||||
for opt in self.question.options.all()
|
||||
]
|
||||
return d
|
||||
|
||||
def save_input(self, position, value):
|
||||
answers = [a for a in position.answerlist if a.question_id == self.question.id]
|
||||
if answers:
|
||||
answers = {self.question: answers[0]}
|
||||
else:
|
||||
answers = {}
|
||||
_save_answers(position, answers, {self.question: value})
|
||||
|
||||
def current_value(self, position):
|
||||
answers = [a for a in position.answerlist if a.question_id == self.question.id]
|
||||
if answers:
|
||||
if self.question.type in (Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE):
|
||||
return ",".join([a.idenitifer for a in answers[0].options.all()])
|
||||
else:
|
||||
return answers[0].answer
|
||||
|
||||
|
||||
class SyntheticSessionField(SessionField):
|
||||
def __init__(self, label, help_text, type, identifier, required, save_func, get_func, validate_func):
|
||||
self._label = label
|
||||
self._help_text = help_text
|
||||
self._type = type
|
||||
self._identifier = identifier
|
||||
self._required = required
|
||||
self._save_func = save_func
|
||||
self._get_func = get_func
|
||||
self._validate_func = validate_func
|
||||
super().__init__()
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self._label
|
||||
|
||||
@property
|
||||
def help_text(self):
|
||||
return self._help_text
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def required(self):
|
||||
return self._required
|
||||
|
||||
@property
|
||||
def identifier(self):
|
||||
return self._identifier
|
||||
|
||||
def validation_hints(self):
|
||||
return {}
|
||||
|
||||
def save_input(self, session_data, value):
|
||||
self._save_func(session_data, value)
|
||||
|
||||
def current_value(self, session_data):
|
||||
return self._get_func(session_data)
|
||||
|
||||
def validate_input(self, value):
|
||||
return self._validate_func(value)
|
||||
|
||||
|
||||
def get_checkout_fields(event):
|
||||
fields = []
|
||||
# TODO: support contact_form_fields
|
||||
# TODO: support contact_form_fields_override
|
||||
|
||||
# email
|
||||
fields.append(SyntheticSessionField(
|
||||
label=_("Email"),
|
||||
help_text=None,
|
||||
type=Question.TYPE_STRING, # TODO: Add a type?
|
||||
identifier="email",
|
||||
required=True,
|
||||
get_func=lambda session_data: session_data.get("email"),
|
||||
save_func=lambda session_data, value: session_data.update({"email": value}),
|
||||
validate_func=lambda value: EmailValidator()(value) or value,
|
||||
))
|
||||
|
||||
# TODO: phone
|
||||
# TODO: invoice address
|
||||
return fields
|
||||
|
||||
|
||||
def get_position_fields(event, pos: CartPosition):
|
||||
# TODO: support override sets
|
||||
fields = []
|
||||
|
||||
for q in pos.item.questions_to_ask:
|
||||
fields.append(QuestionField(q))
|
||||
|
||||
return fields
|
||||
|
||||
|
||||
def ensure_fields_are_completed(event, positions, cart_session, invoice_address, all_optional, cart_is_free):
|
||||
try:
|
||||
emailval = EmailValidator()
|
||||
if not cart_session.get('email') and not all_optional:
|
||||
raise IncompleteError(_('Please enter a valid email address.'))
|
||||
if cart_session.get('email'):
|
||||
emailval(cart_session.get('email'))
|
||||
except ValidationError:
|
||||
raise IncompleteError(_('Please enter a valid email address.'))
|
||||
|
||||
address_asked = (
|
||||
event.settings.invoice_address_asked and (not event.settings.invoice_address_not_asked_free or not cart_is_free)
|
||||
)
|
||||
|
||||
if not all_optional:
|
||||
if address_asked:
|
||||
if event.settings.invoice_address_required and (not invoice_address or not invoice_address.street):
|
||||
raise IncompleteError(_('Please enter your invoicing address.'))
|
||||
|
||||
if event.settings.invoice_name_required and (not invoice_address or not invoice_address.name):
|
||||
raise IncompleteError(_('Please enter your name.'))
|
||||
|
||||
for cp in positions:
|
||||
answ = {
|
||||
aw.question_id: aw for aw in cp.answerlist
|
||||
}
|
||||
question_cache = {
|
||||
q.pk: q for q in cp.item.questions_to_ask
|
||||
}
|
||||
|
||||
def question_is_visible(parentid, qvals):
|
||||
if parentid not in question_cache:
|
||||
return False
|
||||
parentq = question_cache[parentid]
|
||||
if parentq.dependency_question_id and not question_is_visible(parentq.dependency_question_id,
|
||||
parentq.dependency_values):
|
||||
return False
|
||||
if parentid not in answ:
|
||||
return False
|
||||
return (
|
||||
('True' in qvals and answ[parentid].answer == 'True')
|
||||
or ('False' in qvals and answ[parentid].answer == 'False')
|
||||
or (any(qval in [o.identifier for o in answ[parentid].options.all()] for qval in qvals))
|
||||
)
|
||||
|
||||
def question_is_required(q):
|
||||
return (
|
||||
q.required and
|
||||
(not q.dependency_question_id or question_is_visible(q.dependency_question_id, q.dependency_values))
|
||||
)
|
||||
|
||||
if not all_optional:
|
||||
for q in cp.item.questions_to_ask:
|
||||
if question_is_required(q) and q.id not in answ:
|
||||
raise IncompleteError(_('Please fill in answers to all required questions.'))
|
||||
if cp.item.ask_attendee_data and event.settings.get('attendee_names_required', as_type=bool) \
|
||||
and not cp.attendee_name_parts:
|
||||
raise IncompleteError(_('Please fill in answers to all required questions.'))
|
||||
if cp.item.ask_attendee_data and event.settings.get('attendee_emails_required', as_type=bool) \
|
||||
and cp.attendee_email is None:
|
||||
raise IncompleteError(_('Please fill in answers to all required questions.'))
|
||||
if cp.item.ask_attendee_data and event.settings.get('attendee_company_required', as_type=bool) \
|
||||
and cp.company is None:
|
||||
raise IncompleteError(_('Please fill in answers to all required questions.'))
|
||||
if cp.item.ask_attendee_data and event.settings.get('attendee_addresses_required', as_type=bool) \
|
||||
and (cp.street is None and cp.city is None and cp.country is None):
|
||||
raise IncompleteError(_('Please fill in answers to all required questions.'))
|
||||
|
||||
responses = question_form_fields.send(sender=event, position=cp)
|
||||
form_data = cp.meta_info_data.get('question_form_data', {})
|
||||
for r, response in sorted(responses, key=lambda r: str(r[0])):
|
||||
for key, value in response.items():
|
||||
if value.required and not form_data.get(key):
|
||||
raise IncompleteError(_('Please fill in answers to all required questions.'))
|
||||
@@ -0,0 +1,132 @@
|
||||
import copy
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from pretix.base.storelogic import IncompleteError
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
|
||||
|
||||
def payment_is_applicable(event, total, cart_positions, invoice_address, cart_session, request):
|
||||
for cartpos in cart_positions:
|
||||
if cartpos.requires_approval(invoice_address=invoice_address):
|
||||
if 'payments' in cart_session:
|
||||
del cart_session['payments']
|
||||
return False
|
||||
|
||||
used_providers = {p['provider'] for p in cart_session.get('payments', [])}
|
||||
for provider in event.get_payment_providers().values():
|
||||
if provider.is_implicit(request) if callable(provider.is_implicit) else provider.is_implicit:
|
||||
# TODO: do we need a different is_allowed for storefrontapi?
|
||||
if provider.is_allowed(request, total=total):
|
||||
cart_session['payments'] = [
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'provider': provider.identifier,
|
||||
'multi_use_supported': False,
|
||||
'min_value': None,
|
||||
'max_value': None,
|
||||
'info_data': {},
|
||||
}
|
||||
]
|
||||
return False
|
||||
elif provider.identifier in used_providers:
|
||||
# is_allowed might have changed, e.g. after add-on selection
|
||||
cart_session['payments'] = [p for p in cart_session['payments'] if
|
||||
p['provider'] != provider.identifier]
|
||||
return True
|
||||
|
||||
|
||||
def current_selected_payments(event, total, cart_session, total_includes_payment_fees=False, fail=False):
|
||||
def _remove_payment(payment_id):
|
||||
cart_session['payments'] = [p for p in cart_session['payments'] if p.get('id') != payment_id]
|
||||
|
||||
raw_payments = copy.deepcopy(cart_session.get('payments', []))
|
||||
payments = []
|
||||
total_remaining = total
|
||||
for p in raw_payments:
|
||||
# This algorithm of treating min/max values and fees needs to stay in sync between the following
|
||||
# places in the code base:
|
||||
# - pretix.base.services.cart.get_fees
|
||||
# - pretix.base.services.orders._get_fees
|
||||
# - pretix.presale.storelogic.payment.current_selected_payments
|
||||
if p.get('min_value') and total_remaining < Decimal(p['min_value']):
|
||||
_remove_payment(p['id'])
|
||||
if fail:
|
||||
raise IncompleteError(
|
||||
_('Your selected payment method can only be used for a payment of at least {amount}.').format(
|
||||
amount=money_filter(Decimal(p['min_value']), event.currency)
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
to_pay = total_remaining
|
||||
if p.get('max_value') and to_pay > Decimal(p['max_value']):
|
||||
to_pay = min(to_pay, Decimal(p['max_value']))
|
||||
|
||||
pprov = event.get_payment_providers(cached=True).get(p['provider'])
|
||||
if not pprov:
|
||||
_remove_payment(p['id'])
|
||||
continue
|
||||
|
||||
if not total_includes_payment_fees:
|
||||
fee = pprov.calculate_fee(to_pay)
|
||||
total_remaining += fee
|
||||
to_pay += fee
|
||||
else:
|
||||
fee = Decimal('0.00')
|
||||
|
||||
if p.get('max_value') and to_pay > Decimal(p['max_value']):
|
||||
to_pay = min(to_pay, Decimal(p['max_value']))
|
||||
|
||||
p['payment_amount'] = to_pay
|
||||
p['provider_name'] = pprov.public_name
|
||||
p['pprov'] = pprov
|
||||
p['fee'] = fee
|
||||
total_remaining -= to_pay
|
||||
payments.append(p)
|
||||
return payments
|
||||
|
||||
|
||||
def ensure_payment_is_completed(event, total, cart_session, request):
|
||||
def _remove_payment(payment_id):
|
||||
cart_session['payments'] = [p for p in cart_session['payments'] if p.get('id') != payment_id]
|
||||
|
||||
if not cart_session.get('payments'):
|
||||
raise IncompleteError(_('Please select a payment method to proceed.'))
|
||||
|
||||
selected = current_selected_payments(event, total, cart_session, fail=True, total_includes_payment_fees=True)
|
||||
if sum(p['payment_amount'] for p in selected) != total:
|
||||
raise IncompleteError(_('Please select a payment method to proceed.'))
|
||||
|
||||
if len([p for p in selected if not p['multi_use_supported']]) > 1:
|
||||
raise ImproperlyConfigured('Multiple non-multi-use providers in session, should never happen')
|
||||
|
||||
for p in selected:
|
||||
# TODO: do we need a different is_allowed for storefrontapi?
|
||||
if not p['pprov'] or not p['pprov'].is_enabled or not p['pprov'].is_allowed(request, total=total):
|
||||
_remove_payment(p['id'])
|
||||
if p['payment_amount']:
|
||||
raise IncompleteError(_('Please select a payment method to proceed.'))
|
||||
|
||||
if not p['multi_use_supported'] and not p['pprov'].payment_is_valid_session(request):
|
||||
raise IncompleteError(_('The payment information you entered was incomplete.'))
|
||||
|
||||
|
||||
def current_payments_valid(cart_session, amount):
|
||||
singleton_payments = [p for p in cart_session.get('payments', []) if not p.get('multi_use_supported')]
|
||||
if len(singleton_payments) > 1:
|
||||
return False
|
||||
|
||||
matched = Decimal('0.00')
|
||||
for p in cart_session.get('payments', []):
|
||||
if p.get('min_value') and (amount - matched) < Decimal(p['min_value']):
|
||||
continue
|
||||
if p.get('max_value') and (amount - matched) > Decimal(p['max_value']):
|
||||
matched += Decimal(p['max_value'])
|
||||
else:
|
||||
matched = Decimal('0.00')
|
||||
|
||||
return matched == Decimal('0.00'), amount - matched
|
||||
@@ -0,0 +1,396 @@
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import (
|
||||
Count, Exists, IntegerField, OuterRef, Prefetch, Q, Value,
|
||||
)
|
||||
from django.db.models.lookups import Exact
|
||||
|
||||
from pretix.base.models import (
|
||||
ItemVariation, Quota, SalesChannel, SeatCategoryMapping,
|
||||
)
|
||||
from pretix.base.models.items import (
|
||||
ItemAddOn, ItemBundle, SubEventItem, SubEventItemVariation,
|
||||
)
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.base.timemachine import time_machine_now
|
||||
from pretix.presale.signals import item_description
|
||||
|
||||
|
||||
def item_group_by_category(items):
|
||||
return sorted(
|
||||
[
|
||||
# a group is a tuple of a category and a list of items
|
||||
(cat, [i for i in items if i.category == cat])
|
||||
for cat in set([i.category for i in items])
|
||||
# insert categories into a set for uniqueness
|
||||
# a set is unsorted, so sort again by category
|
||||
],
|
||||
key=lambda group: (group[0].position, group[0].id) if (group[0] is not None and group[0].id is not None) else (0, 0)
|
||||
)
|
||||
|
||||
|
||||
def get_items_for_product_list(event, *, channel: SalesChannel, subevent=None, voucher=None, require_seat=0,
|
||||
base_qs=None, allow_addons=False, allow_cross_sell=False,
|
||||
quota_cache=None, filter_items=None, filter_categories=None, memberships=None,
|
||||
ignore_hide_sold_out_for_item_ids=None):
|
||||
base_qs_set = base_qs is not None
|
||||
base_qs = base_qs if base_qs is not None else event.items
|
||||
|
||||
requires_seat = Exists(
|
||||
SeatCategoryMapping.objects.filter(
|
||||
product_id=OuterRef('pk'),
|
||||
subevent=subevent
|
||||
)
|
||||
)
|
||||
if not event.settings.seating_choice:
|
||||
requires_seat = Value(0, output_field=IntegerField())
|
||||
|
||||
variation_q = (
|
||||
Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()) | Q(available_from_mode='info')) &
|
||||
Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()) | Q(available_until_mode='info'))
|
||||
)
|
||||
if not voucher or not voucher.show_hidden_items:
|
||||
variation_q &= Q(hide_without_voucher=False)
|
||||
|
||||
if memberships is not None:
|
||||
prefetch_membership_types = ['require_membership_types']
|
||||
else:
|
||||
prefetch_membership_types = []
|
||||
|
||||
prefetch_var = Prefetch(
|
||||
'variations',
|
||||
to_attr='available_variations',
|
||||
queryset=ItemVariation.objects.using(settings.DATABASE_REPLICA).annotate(
|
||||
subevent_disabled=Exists(
|
||||
SubEventItemVariation.objects.filter(
|
||||
Q(disabled=True)
|
||||
| (Exact(OuterRef('available_from_mode'), 'hide') & Q(available_from__gt=time_machine_now()))
|
||||
| (Exact(OuterRef('available_until_mode'), 'hide') & Q(available_until__lt=time_machine_now())),
|
||||
variation_id=OuterRef('pk'),
|
||||
subevent=subevent,
|
||||
)
|
||||
),
|
||||
).filter(
|
||||
variation_q,
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels=channel),
|
||||
active=True,
|
||||
quotas__isnull=False,
|
||||
subevent_disabled=False
|
||||
).prefetch_related(
|
||||
*prefetch_membership_types,
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=event.quotas.using(settings.DATABASE_REPLICA).filter(
|
||||
subevent=subevent).select_related("subevent"))
|
||||
).distinct()
|
||||
)
|
||||
prefetch_quotas = Prefetch(
|
||||
'quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=event.quotas.using(settings.DATABASE_REPLICA).filter(subevent=subevent).select_related("subevent")
|
||||
)
|
||||
prefetch_bundles = Prefetch(
|
||||
'bundles',
|
||||
queryset=ItemBundle.objects.using(settings.DATABASE_REPLICA).prefetch_related(
|
||||
Prefetch('bundled_item',
|
||||
queryset=event.items.using(settings.DATABASE_REPLICA).select_related(
|
||||
'tax_rule').prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=event.quotas.using(settings.DATABASE_REPLICA).filter(
|
||||
subevent=subevent)),
|
||||
)),
|
||||
Prefetch('bundled_variation',
|
||||
queryset=ItemVariation.objects.using(
|
||||
settings.DATABASE_REPLICA
|
||||
).select_related('item', 'item__tax_rule').filter(item__event=event).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=event.quotas.using(settings.DATABASE_REPLICA).filter(
|
||||
subevent=subevent)),
|
||||
)),
|
||||
)
|
||||
)
|
||||
|
||||
items = base_qs.using(settings.DATABASE_REPLICA).filter_available(
|
||||
channel=channel.identifier, voucher=voucher, allow_addons=allow_addons, allow_cross_sell=allow_cross_sell
|
||||
).select_related(
|
||||
'category', 'tax_rule', # for re-grouping
|
||||
'hidden_if_available',
|
||||
).prefetch_related(
|
||||
*prefetch_membership_types,
|
||||
Prefetch(
|
||||
'hidden_if_item_available',
|
||||
queryset=event.items.annotate(
|
||||
has_variations=Count('variations'),
|
||||
).prefetch_related(
|
||||
prefetch_var,
|
||||
prefetch_quotas,
|
||||
prefetch_bundles,
|
||||
)
|
||||
),
|
||||
prefetch_quotas,
|
||||
prefetch_var,
|
||||
prefetch_bundles,
|
||||
).annotate(
|
||||
quotac=Count('quotas'),
|
||||
has_variations=Count('variations'),
|
||||
subevent_disabled=Exists(
|
||||
SubEventItem.objects.filter(
|
||||
Q(disabled=True)
|
||||
| (Exact(OuterRef('available_from_mode'), 'hide') & Q(available_from__gt=time_machine_now()))
|
||||
| (Exact(OuterRef('available_until_mode'), 'hide') & Q(available_until__lt=time_machine_now())),
|
||||
item_id=OuterRef('pk'),
|
||||
subevent=subevent,
|
||||
)
|
||||
),
|
||||
mandatory_priced_addons=Exists(
|
||||
ItemAddOn.objects.filter(
|
||||
base_item_id=OuterRef('pk'),
|
||||
min_count__gte=1,
|
||||
price_included=False
|
||||
)
|
||||
),
|
||||
requires_seat=requires_seat,
|
||||
).filter(
|
||||
quotac__gt=0, subevent_disabled=False,
|
||||
).order_by('category__position', 'category_id', 'position', 'name')
|
||||
if require_seat:
|
||||
items = items.filter(requires_seat__gt=0)
|
||||
elif require_seat is not None:
|
||||
items = items.filter(requires_seat=0)
|
||||
|
||||
if filter_items:
|
||||
items = items.filter(pk__in=[a for a in filter_items if a.isdigit()])
|
||||
if filter_categories:
|
||||
items = items.filter(category_id__in=[a for a in filter_categories if a.isdigit()])
|
||||
|
||||
display_add_to_cart = False
|
||||
quota_cache_key = f'item_quota_cache:{subevent.id if subevent else 0}:{channel.identifier}:{bool(require_seat)}'
|
||||
quota_cache = quota_cache or event.cache.get(quota_cache_key) or {}
|
||||
quota_cache_existed = bool(quota_cache)
|
||||
|
||||
if subevent:
|
||||
item_price_override = subevent.item_price_overrides
|
||||
var_price_override = subevent.var_price_overrides
|
||||
else:
|
||||
item_price_override = {}
|
||||
var_price_override = {}
|
||||
|
||||
restrict_vars = set()
|
||||
if voucher and voucher.quota_id:
|
||||
# If a voucher is set to a specific quota, we need to filter out on that level
|
||||
restrict_vars = set(voucher.quota.variations.all())
|
||||
|
||||
quotas_to_compute = []
|
||||
for item in items:
|
||||
assert item.event_id == event.pk
|
||||
item.event = event # save a database query if this is looked up
|
||||
if item.has_variations:
|
||||
for v in item.available_variations:
|
||||
for q in v._subevent_quotas:
|
||||
if q.pk not in quota_cache:
|
||||
quotas_to_compute.append(q)
|
||||
else:
|
||||
for q in item._subevent_quotas:
|
||||
if q.pk not in quota_cache:
|
||||
quotas_to_compute.append(q)
|
||||
|
||||
if quotas_to_compute:
|
||||
qa = QuotaAvailability()
|
||||
qa.queue(*quotas_to_compute)
|
||||
qa.compute()
|
||||
quota_cache.update({q.pk: r for q, r in qa.results.items()})
|
||||
|
||||
for item in items:
|
||||
if voucher and voucher.item_id and voucher.variation_id:
|
||||
# Restrict variations if the voucher only allows one
|
||||
item.available_variations = [v for v in item.available_variations
|
||||
if v.pk == voucher.variation_id]
|
||||
|
||||
if channel.type_instance.unlimited_items_per_order:
|
||||
max_per_order = sys.maxsize
|
||||
else:
|
||||
max_per_order = item.max_per_order or int(event.settings.max_items_per_order)
|
||||
|
||||
if item.hidden_if_available:
|
||||
q = item.hidden_if_available.availability(_cache=quota_cache)
|
||||
if q[0] == Quota.AVAILABILITY_OK:
|
||||
item._remove = True
|
||||
continue
|
||||
|
||||
if item.hidden_if_item_available:
|
||||
if item.hidden_if_item_available.has_variations:
|
||||
dependency_available = any(
|
||||
var.check_quotas(subevent=subevent, _cache=quota_cache, include_bundled=True)[0] == Quota.AVAILABILITY_OK
|
||||
for var in item.hidden_if_item_available.available_variations
|
||||
)
|
||||
else:
|
||||
q = item.hidden_if_item_available.check_quotas(subevent=subevent, _cache=quota_cache, include_bundled=True)
|
||||
dependency_available = q[0] == Quota.AVAILABILITY_OK
|
||||
if dependency_available:
|
||||
item._remove = True
|
||||
continue
|
||||
|
||||
if item.require_membership and item.require_membership_hidden:
|
||||
if not memberships or not any([m.membership_type in item.require_membership_types.all() for m in memberships]):
|
||||
item._remove = True
|
||||
continue
|
||||
|
||||
item.current_unavailability_reason = item.unavailability_reason(has_voucher=voucher, subevent=subevent)
|
||||
|
||||
item.description = str(item.description)
|
||||
for recv, resp in item_description.send(sender=event, item=item, variation=None, subevent=subevent):
|
||||
if resp:
|
||||
item.description += ("<br/>" if item.description else "") + resp
|
||||
|
||||
if not item.has_variations:
|
||||
item._remove = False
|
||||
if not bool(item._subevent_quotas):
|
||||
item._remove = True
|
||||
continue
|
||||
|
||||
if voucher and (voucher.allow_ignore_quota or voucher.block_quota):
|
||||
item.cached_availability = (
|
||||
Quota.AVAILABILITY_OK, voucher.max_usages - voucher.redeemed
|
||||
)
|
||||
else:
|
||||
item.cached_availability = list(
|
||||
item.check_quotas(subevent=subevent, _cache=quota_cache, include_bundled=True)
|
||||
)
|
||||
|
||||
if not (
|
||||
ignore_hide_sold_out_for_item_ids and item.pk in ignore_hide_sold_out_for_item_ids
|
||||
) and event.settings.hide_sold_out and item.cached_availability[0] < Quota.AVAILABILITY_RESERVED:
|
||||
item._remove = True
|
||||
continue
|
||||
|
||||
item.order_max = min(
|
||||
item.cached_availability[1]
|
||||
if item.cached_availability[1] is not None else sys.maxsize,
|
||||
max_per_order
|
||||
)
|
||||
|
||||
original_price = item_price_override.get(item.pk, item.default_price)
|
||||
voucher_reduced = False
|
||||
if voucher:
|
||||
price = voucher.calculate_price(original_price)
|
||||
voucher_reduced = price < original_price
|
||||
include_bundled = not voucher.all_bundles_included
|
||||
else:
|
||||
price = original_price
|
||||
include_bundled = True
|
||||
|
||||
item.display_price = item.tax(price, currency=event.currency, include_bundled=include_bundled)
|
||||
if item.free_price and item.free_price_suggestion is not None and not voucher_reduced:
|
||||
item.suggested_price = item.tax(max(price, item.free_price_suggestion), currency=event.currency, include_bundled=include_bundled)
|
||||
else:
|
||||
item.suggested_price = item.display_price
|
||||
|
||||
if price != original_price:
|
||||
item.original_price = item.tax(original_price, currency=event.currency, include_bundled=True)
|
||||
else:
|
||||
item.original_price = (
|
||||
item.tax(item.original_price, currency=event.currency, include_bundled=True,
|
||||
base_price_is='net' if event.settings.display_net_prices else 'gross') # backwards-compat
|
||||
if item.original_price else None
|
||||
)
|
||||
if not display_add_to_cart:
|
||||
display_add_to_cart = not item.requires_seat and item.order_max > 0
|
||||
else:
|
||||
for var in item.available_variations:
|
||||
if var.require_membership and var.require_membership_hidden:
|
||||
if not memberships or not any([m.membership_type in var.require_membership_types.all() for m in memberships]):
|
||||
var._remove = True
|
||||
continue
|
||||
|
||||
var.description = str(var.description)
|
||||
for recv, resp in item_description.send(sender=event, item=item, variation=var, subevent=subevent):
|
||||
if resp:
|
||||
var.description += ("<br/>" if var.description else "") + resp
|
||||
|
||||
if voucher and (voucher.allow_ignore_quota or voucher.block_quota):
|
||||
var.cached_availability = (
|
||||
Quota.AVAILABILITY_OK, voucher.max_usages - voucher.redeemed
|
||||
)
|
||||
else:
|
||||
var.cached_availability = list(
|
||||
var.check_quotas(subevent=subevent, _cache=quota_cache, include_bundled=True)
|
||||
)
|
||||
|
||||
var.order_max = min(
|
||||
var.cached_availability[1]
|
||||
if var.cached_availability[1] is not None else sys.maxsize,
|
||||
max_per_order
|
||||
)
|
||||
|
||||
original_price = var_price_override.get(var.pk, var.price)
|
||||
voucher_reduced = False
|
||||
if voucher:
|
||||
price = voucher.calculate_price(original_price)
|
||||
voucher_reduced = price < original_price
|
||||
include_bundled = not voucher.all_bundles_included
|
||||
else:
|
||||
price = original_price
|
||||
include_bundled = True
|
||||
|
||||
var.display_price = var.tax(price, currency=event.currency, include_bundled=include_bundled)
|
||||
|
||||
if item.free_price and var.free_price_suggestion is not None and not voucher_reduced:
|
||||
var.suggested_price = item.tax(max(price, var.free_price_suggestion), currency=event.currency,
|
||||
include_bundled=include_bundled)
|
||||
elif item.free_price and item.free_price_suggestion is not None and not voucher_reduced:
|
||||
var.suggested_price = item.tax(max(price, item.free_price_suggestion), currency=event.currency,
|
||||
include_bundled=include_bundled)
|
||||
else:
|
||||
var.suggested_price = var.display_price
|
||||
|
||||
if price != original_price:
|
||||
var.original_price = var.tax(original_price, currency=event.currency, include_bundled=True)
|
||||
else:
|
||||
var.original_price = (
|
||||
var.tax(var.original_price or item.original_price, currency=event.currency,
|
||||
include_bundled=True,
|
||||
base_price_is='net' if event.settings.display_net_prices else 'gross') # backwards-compat
|
||||
) if var.original_price or item.original_price else None
|
||||
|
||||
if not display_add_to_cart:
|
||||
display_add_to_cart = not item.requires_seat and var.order_max > 0
|
||||
|
||||
var.current_unavailability_reason = var.unavailability_reason(has_voucher=voucher, subevent=subevent)
|
||||
|
||||
item.original_price = (
|
||||
item.tax(item.original_price, currency=event.currency, include_bundled=True,
|
||||
base_price_is='net' if event.settings.display_net_prices else 'gross') # backwards-compat
|
||||
if item.original_price else None
|
||||
)
|
||||
|
||||
item.available_variations = [
|
||||
v for v in item.available_variations if v._subevent_quotas and (
|
||||
not voucher or not voucher.quota_id or v in restrict_vars
|
||||
) and not getattr(v, '_remove', False)
|
||||
]
|
||||
|
||||
if not (ignore_hide_sold_out_for_item_ids and item.pk in ignore_hide_sold_out_for_item_ids) and event.settings.hide_sold_out:
|
||||
item.available_variations = [v for v in item.available_variations
|
||||
if v.cached_availability[0] >= Quota.AVAILABILITY_RESERVED]
|
||||
|
||||
if voucher and voucher.variation_id:
|
||||
item.available_variations = [v for v in item.available_variations
|
||||
if v.pk == voucher.variation_id]
|
||||
|
||||
if len(item.available_variations) > 0:
|
||||
item.min_price = min([v.display_price.net if event.settings.display_net_prices else
|
||||
v.display_price.gross for v in item.available_variations])
|
||||
item.max_price = max([v.display_price.net if event.settings.display_net_prices else
|
||||
v.display_price.gross for v in item.available_variations])
|
||||
item.best_variation_availability = max([v.cached_availability[0] for v in item.available_variations])
|
||||
|
||||
item._remove = not bool(item.available_variations)
|
||||
|
||||
if not quota_cache_existed and not voucher and not allow_addons and not base_qs_set and not filter_items and not filter_categories:
|
||||
event.cache.set(quota_cache_key, quota_cache, 5)
|
||||
items = [item for item in items
|
||||
if (len(item.available_variations) > 0 or not item.has_variations) and not item._remove]
|
||||
return items, display_add_to_cart
|
||||
@@ -67,6 +67,7 @@ class EventSlugBanlistValidator(BanlistValidator):
|
||||
'_global',
|
||||
'__debug__',
|
||||
'api',
|
||||
'storefrontapi',
|
||||
'events',
|
||||
'csp_report',
|
||||
'widget',
|
||||
@@ -91,6 +92,7 @@ class OrganizerSlugBanlistValidator(BanlistValidator):
|
||||
'__debug__',
|
||||
'about',
|
||||
'api',
|
||||
'storefrontapi',
|
||||
'csp_report',
|
||||
'widget',
|
||||
'lead',
|
||||
|
||||
@@ -40,5 +40,5 @@ class PretixControlConfig(AppConfig):
|
||||
label = 'pretixcontrol'
|
||||
|
||||
def ready(self):
|
||||
from .views import dashboards # noqa
|
||||
from . import logdisplay # noqa
|
||||
from .views import dashboards # noqa
|
||||
|
||||
@@ -63,6 +63,7 @@ from pretix.base.forms import (
|
||||
)
|
||||
from pretix.base.models import Event, Organizer, TaxRule, Team
|
||||
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.services.placeholders import FormPlaceholderMixin
|
||||
from pretix.base.settings import (
|
||||
@@ -1504,6 +1505,11 @@ class TaxRuleLineForm(I18nForm):
|
||||
('require_approval', _('Order requires approval')),
|
||||
],
|
||||
)
|
||||
code = forms.ChoiceField(
|
||||
label=_("Tax code"),
|
||||
choices=[("", _("Default tax code")), *TAX_CODE_LISTS],
|
||||
required=False,
|
||||
)
|
||||
rate = forms.DecimalField(
|
||||
label=_('Deviating tax rate'),
|
||||
max_digits=10, decimal_places=2,
|
||||
@@ -1518,6 +1524,43 @@ 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):
|
||||
# compatibility shim for django-i18nfield library
|
||||
@@ -1529,8 +1572,16 @@ class I18nBaseFormSet(I18nFormSetMixin, forms.BaseFormSet):
|
||||
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(
|
||||
TaxRuleLineForm, formset=I18nBaseFormSet,
|
||||
TaxRuleLineForm, formset=BaseTaxRuleLineFormSet,
|
||||
can_order=True, can_delete=True, extra=0
|
||||
)
|
||||
|
||||
@@ -1538,7 +1589,16 @@ TaxRuleLineFormSet = formset_factory(
|
||||
class TaxRuleForm(I18nModelForm):
|
||||
class Meta:
|
||||
model = TaxRule
|
||||
fields = ['name', 'rate', 'price_includes_tax', 'eu_reverse_charge', 'home_country', 'internal_name', 'keep_gross_if_rate_changes']
|
||||
fields = [
|
||||
'name',
|
||||
'rate',
|
||||
'price_includes_tax',
|
||||
'code',
|
||||
'eu_reverse_charge',
|
||||
'home_country',
|
||||
'internal_name',
|
||||
'keep_gross_if_rate_changes'
|
||||
]
|
||||
|
||||
|
||||
class WidgetCodeForm(forms.Form):
|
||||
|
||||
@@ -490,7 +490,9 @@ class OrderPositionChangeForm(forms.Form):
|
||||
)
|
||||
operation_secret = forms.BooleanField(
|
||||
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(
|
||||
required=False,
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
{% bootstrap_field form.name layout="control" %}
|
||||
{% bootstrap_field form.internal_name layout="control" %}
|
||||
{% bootstrap_field form.rate addon_after="%" layout="control" %}
|
||||
{% bootstrap_field form.code layout="control" %}
|
||||
{% bootstrap_field form.price_includes_tax layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
@@ -52,6 +53,18 @@
|
||||
{% trans "All of these rules will only apply if an invoice address is set." %}
|
||||
</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 }}">
|
||||
{{ formset.management_form }}
|
||||
{% bootstrap_formset_errors formset %}
|
||||
@@ -65,14 +78,17 @@
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-3">
|
||||
{% 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="" %}
|
||||
</div>
|
||||
<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.rate layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-2 text-right flip">
|
||||
<div class="col-sm-6 col-md-3 col-lg-4 col-sm-offset-6 col-md-offset-0">
|
||||
{% 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>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default" data-formset-move-down-button>
|
||||
@@ -80,12 +96,6 @@
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</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>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
@@ -100,14 +110,17 @@
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-3">
|
||||
{% 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="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-3">
|
||||
{% bootstrap_field form.action layout='inline' form_group_class="" %}
|
||||
{% bootstrap_field form.rate layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-2 text-right flip">
|
||||
<div class="col-sm-6 col-md-3 col-lg-4 col-sm-offset-6 col-md-offset-0">
|
||||
{% 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>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default" data-formset-move-down-button>
|
||||
@@ -115,12 +128,6 @@
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -220,7 +220,6 @@
|
||||
{% 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_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.limit_sales_channels layout="control" %}
|
||||
{% bootstrap_field formset.empty_form.hide_without_voucher layout="control" %}
|
||||
|
||||
@@ -202,6 +202,12 @@
|
||||
+ {{ position.tax_rate }}%)
|
||||
</small>
|
||||
{% endif %}
|
||||
{% if position.tax_code %}
|
||||
<br>
|
||||
<small>
|
||||
{{ position.get_tax_code_display }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-sm-4 field-container">
|
||||
{% bootstrap_field position.form.price addon_after=request.event.currency layout='inline' %}
|
||||
@@ -420,6 +426,12 @@
|
||||
+ {{ fee.tax_rate }}%)
|
||||
</small>
|
||||
{% endif %}
|
||||
{% if fee.tax_code %}
|
||||
<br>
|
||||
<small>
|
||||
{{ fee.get_tax_code_display }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-sm-4 field-container">
|
||||
{% bootstrap_field fee.form.value addon_after=request.event.currency layout='inline' %}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<th>{% trans "Date" %}</th>
|
||||
<th>{% trans "Product" %}</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 "Single price" %}</th>
|
||||
<th class="text-right flip">{% trans "Total tax value" %}</th>
|
||||
@@ -52,6 +53,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right flip">{{ t.tax_rate }} %</td>
|
||||
<td>{{ t.get_tax_code_display }}</td>
|
||||
<td class="text-right flip">{{ t.count }} ×</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>
|
||||
@@ -64,8 +66,8 @@
|
||||
<td>
|
||||
<strong>{% trans "Sum" %}</strong>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-right flip">
|
||||
<strong>
|
||||
|
||||
@@ -1197,17 +1197,22 @@ class TaxCreate(EventSettingsViewMixin, EventPermissionRequiredMixin, CreateView
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = None
|
||||
form = self.get_form()
|
||||
form = self.form
|
||||
if form.is_valid() and self.formset.is_valid():
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
@cached_property
|
||||
def form(self):
|
||||
return self.get_form()
|
||||
|
||||
@cached_property
|
||||
def formset(self):
|
||||
return TaxRuleLineFormSet(
|
||||
data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
parent_form=self.form,
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -1248,17 +1253,22 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(self.get_queryset())
|
||||
form = self.get_form()
|
||||
form = self.form
|
||||
if form.is_valid() and self.formset.is_valid():
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
@cached_property
|
||||
def form(self):
|
||||
return self.get_form()
|
||||
|
||||
@cached_property
|
||||
def formset(self):
|
||||
return TaxRuleLineFormSet(
|
||||
data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
parent_form=self.form,
|
||||
initial=json.loads(self.object.custom_rules) if self.object.custom_rules else []
|
||||
)
|
||||
|
||||
|
||||
@@ -2241,6 +2241,8 @@ class OrderContactChange(OrderView):
|
||||
changed = True
|
||||
self.order.secret = generate_secret()
|
||||
for op in self.order.all_positions.all():
|
||||
op.web_secret = generate_secret()
|
||||
op.save(update_fields=["web_secret"])
|
||||
assign_ticket_secret(
|
||||
self.request.event, position=op, force_invalidate=True, save=True
|
||||
)
|
||||
|
||||
+2119
-1846
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -622,40 +622,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -705,20 +705,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2234
-1854
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2021-09-15 11:22+0000\n"
|
||||
"Last-Translator: Mohamed Tawfiq <mtawfiq@wafyapp.com>\n"
|
||||
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -656,40 +656,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr "تباين اللون سيئ للخلفية البيضاء، الرجاء اختيار لون غامق."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "البحث في الاستفسارات"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "الكل"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "لا شيء"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "المختارة فقط"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "قم باستخدم اسم مختلف داخليا"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "اضغط لاغلاق الصفحة"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr "لم تقم بحفظ التعديلات!"
|
||||
|
||||
@@ -753,20 +753,20 @@ msgstr "ستسترد %(currency)%(amount)"
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr "الرجاء إدخال المبلغ الذي يمكن للمنظم الاحتفاظ به."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "الرجاء إدخال عدد لأحد أنواع التذاكر."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "مطلوب"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "المنطقة الزمنية:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "التوقيت المحلي:"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2207
-1855
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2020-12-19 07:00+0000\n"
|
||||
"Last-Translator: albert <albert.serra.monner@gmail.com>\n"
|
||||
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
@@ -623,40 +623,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -710,22 +710,22 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
#, fuzzy
|
||||
#| msgid "Cart expired"
|
||||
msgid "required"
|
||||
msgstr "Cistella expirada"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2206
-1839
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2023-09-15 06:00+0000\n"
|
||||
"Last-Translator: Michael <michael.happl@gmx.at>\n"
|
||||
"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 "
|
||||
"tmavší odstín."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Hledaný výraz"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Všechny"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Žádný"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Pouze vybrané"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Interně používat jiný název"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Kliknutím zavřete"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Zadejte částku, kterou si organizátor může ponechat."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Zadejte prosím množství pro jeden z typů vstupenek."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "povinný"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Časové pásmo:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Místní čas:"
|
||||
|
||||
|
||||
+2134
-1843
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -623,40 +623,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -706,20 +706,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2202
-1849
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-07-10 15:00+0000\n"
|
||||
"Last-Translator: Nikolai <nikolai@lengefeldt.de>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -670,40 +670,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Ingen"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Klik for at lukke"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
#, fuzzy
|
||||
#| msgid "Cart expired"
|
||||
msgid "required"
|
||||
msgstr "Kurv udløbet"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Tidszone:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Din lokaltid:"
|
||||
|
||||
|
||||
+2209
-1868
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-09-10 07:17+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"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 "
|
||||
"Hintergrund. Bitte wählen Sie eine dunklere Farbe."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Suchbegriff"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Keine"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Nur ausgewählte"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr "Geben Sie eine Seitenzahl zwischen 1 und %(max)s ein."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr "Ungültige Seitenzahl."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Intern einen anderen Namen verwenden"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Klicken zum Schließen"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Bitte geben Sie den Betrag ein, den der Veranstalter einbehalten darf."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Bitte tragen Sie eine Menge für eines der Produkte ein."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "verpflichtend"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Zeitzone:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Deine lokale Zeit:"
|
||||
|
||||
|
||||
@@ -66,10 +66,12 @@ BSD
|
||||
bspw
|
||||
Bokmål
|
||||
Boleto
|
||||
Buchhaltungs
|
||||
Bundles
|
||||
Butterfly
|
||||
bzw
|
||||
ca
|
||||
Ceuta
|
||||
Cc
|
||||
chardet
|
||||
charge
|
||||
@@ -158,9 +160,12 @@ Inc
|
||||
inkl
|
||||
innenname
|
||||
innennamen
|
||||
innergemeinschaftliche
|
||||
Innergemeinschaftlicher
|
||||
Input
|
||||
Installations
|
||||
integrationen
|
||||
intra
|
||||
INV
|
||||
invalidieren
|
||||
invalidiert
|
||||
@@ -177,10 +182,12 @@ Kombitickets
|
||||
Kompatibilitätsmodus
|
||||
Konfigurations
|
||||
Kosovo
|
||||
land
|
||||
landesspezifische
|
||||
Lead
|
||||
Leaflet
|
||||
Linktext
|
||||
lit
|
||||
Logindaten
|
||||
Lösch
|
||||
loszulegen
|
||||
@@ -188,6 +195,7 @@ Ltd
|
||||
max
|
||||
MariaDB
|
||||
MapQuest
|
||||
Melilla
|
||||
Mercado
|
||||
Merchandise
|
||||
Meta
|
||||
@@ -269,6 +277,7 @@ rückabgewickelt
|
||||
Rundungsdifferenzen
|
||||
Sa
|
||||
Saalplan
|
||||
Sammlungsstücken
|
||||
SAQ
|
||||
SCA
|
||||
Scan
|
||||
@@ -357,6 +366,7 @@ USt
|
||||
Überzahlten
|
||||
Validierung
|
||||
Venmo
|
||||
Veranstalterdomain
|
||||
Veranstaltereinstellungen
|
||||
Veranstalterkonten
|
||||
Veranstalterkonto
|
||||
@@ -367,6 +377,7 @@ Veranstalterseite
|
||||
Veranstalterübersicht
|
||||
veranstalterweiten
|
||||
Veranstaltungs
|
||||
Veranstalterdomain
|
||||
veranstaltungsweiten
|
||||
Verfügbarkeitsberechnung
|
||||
Verfügbarkeitsstatus
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-09-10 07:17+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"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 "
|
||||
"Hintergrund. Bitte wähle eine dunklere Farbe."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Suchbegriff"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Keine"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Nur ausgewählte"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr "Gib eine Seitenzahl zwischen 1 und %(max)s ein."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr "Ungültige Seitenzahl."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Intern einen anderen Namen verwenden"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Klicken zum Schließen"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Bitte gib den Betrag ein, den der Veranstalter einbehalten darf."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Bitte trage eine Menge für eines der Produkte ein."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "verpflichtend"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Zeitzone:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Deine lokale Zeit:"
|
||||
|
||||
|
||||
@@ -66,10 +66,12 @@ BSD
|
||||
bspw
|
||||
Bokmål
|
||||
Boleto
|
||||
Buchhaltungs
|
||||
Bundles
|
||||
Butterfly
|
||||
bzw
|
||||
ca
|
||||
Ceuta
|
||||
Cc
|
||||
chardet
|
||||
charge
|
||||
@@ -158,9 +160,12 @@ Inc
|
||||
inkl
|
||||
innenname
|
||||
innennamen
|
||||
innergemeinschaftliche
|
||||
Innergemeinschaftlicher
|
||||
Input
|
||||
Installations
|
||||
integrationen
|
||||
intra
|
||||
INV
|
||||
invalidieren
|
||||
invalidiert
|
||||
@@ -177,10 +182,12 @@ Kombitickets
|
||||
Kompatibilitätsmodus
|
||||
Konfigurations
|
||||
Kosovo
|
||||
land
|
||||
landesspezifische
|
||||
Lead
|
||||
Leaflet
|
||||
Linktext
|
||||
lit
|
||||
Logindaten
|
||||
Lösch
|
||||
loszulegen
|
||||
@@ -188,6 +195,7 @@ Ltd
|
||||
max
|
||||
MariaDB
|
||||
MapQuest
|
||||
Melilla
|
||||
Mercado
|
||||
Merchandise
|
||||
Meta
|
||||
@@ -269,6 +277,7 @@ rückabgewickelt
|
||||
Rundungsdifferenzen
|
||||
Sa
|
||||
Saalplan
|
||||
Sammlungsstücken
|
||||
SAQ
|
||||
SCA
|
||||
Scan
|
||||
@@ -357,6 +366,7 @@ USt
|
||||
Überzahlten
|
||||
Validierung
|
||||
Venmo
|
||||
Veranstalterdomain
|
||||
Veranstaltereinstellungen
|
||||
Veranstalterkonten
|
||||
Veranstalterkonto
|
||||
@@ -367,6 +377,7 @@ Veranstalterseite
|
||||
Veranstalterübersicht
|
||||
veranstalterweiten
|
||||
Veranstaltungs
|
||||
Veranstalterdomain
|
||||
veranstaltungsweiten
|
||||
Verfügbarkeitsberechnung
|
||||
Verfügbarkeitsstatus
|
||||
|
||||
+2119
-1846
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-19 15:34+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -622,40 +622,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -705,20 +705,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2251
-1878
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"PO-Revision-Date: 2019-10-03 19:00+0000\n"
|
||||
"Last-Translator: Chris Spy <chrispiropoulou@hotmail.com>\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-12-22 00:00+0000\n"
|
||||
"Last-Translator: Dimitris Tsimpidis <tsimpidisd@gmail.com>\n"
|
||||
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
"el/>\n"
|
||||
"Language: el\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 3.5.1\n"
|
||||
"X-Generator: Weblate 5.9.2\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -31,7 +31,7 @@ msgstr "Σχόλιο:"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:34
|
||||
msgid "PayPal"
|
||||
msgstr ""
|
||||
msgstr "PayPal"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:35
|
||||
msgid "Venmo"
|
||||
@@ -64,7 +64,7 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:42
|
||||
msgid "SEPA Direct Debit"
|
||||
msgstr ""
|
||||
msgstr "Τραπεζική μεταφορά"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:43
|
||||
msgid "Bancontact"
|
||||
@@ -79,10 +79,8 @@ msgid "SOFORT"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:46
|
||||
#, fuzzy
|
||||
#| msgid "Yes"
|
||||
msgid "eps"
|
||||
msgstr "Ναι"
|
||||
msgstr "EPS"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:47
|
||||
msgid "MyBank"
|
||||
@@ -147,11 +145,11 @@ msgstr "Συνέχεια"
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:317
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:341
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
msgstr "Επιβεβαίωση πληρωμής…"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:254
|
||||
msgid "Payment method unavailable"
|
||||
msgstr ""
|
||||
msgstr "Μη διαθέσιμος τρόπος πληρωμής"
|
||||
|
||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
||||
@@ -176,10 +174,8 @@ msgid "Total"
|
||||
msgstr "Σύνολο"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:291
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Επικοινωνία με το Stripe …"
|
||||
msgstr "Επικοινωνία με την τράπεζα …"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:30
|
||||
msgid "Select a check-in list"
|
||||
@@ -686,40 +682,40 @@ msgstr ""
|
||||
"Το χρώμα σας έχει κακή αντίθεση για κείμενο σε λευκό φόντο, επιλέξτε μια πιο "
|
||||
"σκούρα σκιά."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Όλα"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Κανένας"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Κάντε κλικ για να κλείσετε"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -781,22 +777,22 @@ msgstr "απο %(currency)s %(price)s"
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Εισαγάγετε μια ποσότητα για έναν από τους τύπους εισιτηρίων."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
#, fuzzy
|
||||
#| msgid "Cart expired"
|
||||
msgid "required"
|
||||
msgstr "Το καλάθι έληξε"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2119
-1846
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -622,40 +622,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -705,20 +705,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2230
-1885
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-11-18 15:48+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/es/>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
"js/es/>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\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, "
|
||||
"escoge un tono más oscuro."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Consulta de búsqueda"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Todos"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Ninguno"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Solamente seleccionados"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr "Introduce un número de página entre 1 y %(max)s."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr "Número de página inválido."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Usar un nombre diferente internamente"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Click para cerrar"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Por favor, ingrese el importe que el organizador puede quedarse."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Por favor, introduzca un valor para cada tipo de entrada."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "campo requerido"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Zona horaria:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Su hora local:"
|
||||
|
||||
|
||||
+2119
-1846
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -622,40 +622,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -705,20 +705,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2212
-1840
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-09-06 08:47+0000\n"
|
||||
"Last-Translator: Albizuri <oier@puntu.eus>\n"
|
||||
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -635,40 +635,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Guztiak"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -721,20 +721,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2856
-2484
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2021-11-10 05:00+0000\n"
|
||||
"Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n"
|
||||
"Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
@@ -651,40 +651,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Kaikki"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Käytä toista nimeä sisäisesti"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Sulje klikkaamalla"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr "Sinulla on tallentamattomia muutoksia!"
|
||||
|
||||
@@ -738,22 +738,22 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
#, fuzzy
|
||||
#| msgid "Cart expired"
|
||||
msgid "required"
|
||||
msgstr "Ostoskori on vanhentunut"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Aikavyöhyke:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2213
-1870
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: French\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-12-03 20:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -643,40 +643,40 @@ msgstr ""
|
||||
"Votre choix de couleur n'a pas un bon contraste avec du texte sur un fond "
|
||||
"blanc, SVP choisissez un ton plus sombre."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Requête de recherche"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Tous"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Aucun"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Seuls les sélectionnés"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr "Saisir le numéro de page entre 1 et %(max)s."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr "Numéro de page invalide."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Utiliser un nom différent en interne"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Cliquez pour fermer"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr "Vous avez des modifications non sauvegardées !"
|
||||
|
||||
@@ -729,20 +729,20 @@ msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
"Veuillez indiquer le montant que l'organisateur est autorisé à retenir."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "SVP entrez une quantité pour un de vos types de billets."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "obligatoire"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Fuseau horaire :"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Votre heure locale :"
|
||||
|
||||
|
||||
+2221
-1876
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2022-02-22 22:00+0000\n"
|
||||
"Last-Translator: Ismael Menéndez Fernández <ismael.menendez@balidea.com>\n"
|
||||
"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, "
|
||||
"escolle un ton máis escuro."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Consultar unha procura"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Todos"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Ningún"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Soamente seleccionados"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Usar un nome diferente internamente"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Click para cerrar"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Por favor, ingrese a cantidade que pode conservar o organizador."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Por favor, introduza un valor para cada tipo de entrada."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "campo requirido"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Zona horaria:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "A súa hora local:"
|
||||
|
||||
|
||||
+2123
-1846
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2021-09-24 13:54+0000\n"
|
||||
"Last-Translator: ofirtro <ofir.tro@gmail.com>\n"
|
||||
"Language-Team: Hebrew <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -630,40 +630,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -717,20 +717,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2121
-1846
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-11-17 00:00+0000\n"
|
||||
"Last-Translator: Pavle Ergović <pavleergovic@gmail.com>\n"
|
||||
"Language-Team: Croatian <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/hr/>\n"
|
||||
"Language-Team: Croatian <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
"js/hr/>\n"
|
||||
"Language: hr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -624,40 +624,40 @@ msgid ""
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr ""
|
||||
|
||||
@@ -707,20 +707,20 @@ msgstr ""
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2167
-1854
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2024-11-28 06:00+0000\n"
|
||||
"Last-Translator: Patrick Chilton <chpatrick@gmail.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/hu/>\n"
|
||||
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
"js/hu/>\n"
|
||||
"Language: hu\n"
|
||||
"MIME-Version: 1.0\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 "
|
||||
"árnyalatot."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Összes"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Semmi"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Használj másik nevet"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Bezárásért kattints"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
msgstr "Mentetlen változtatások!"
|
||||
|
||||
@@ -766,22 +766,22 @@ msgstr "%(currency) %(price)-tól"
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Adjon meg egy mennyiséget az egyik jegytípusból."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
#, fuzzy
|
||||
#| msgid "Cart expired"
|
||||
msgid "required"
|
||||
msgstr "A kosár lejárt"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Időzona:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+2231
-1855
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2023-09-20 14:01+0000\n"
|
||||
"Last-Translator: Mahdia Aliyy <mahdlyy.k@gmail.com>\n"
|
||||
"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 "
|
||||
"putih, harap pilih warna yang lebih gelap."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Permintaan pencarian"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Semua"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Tidak ada"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Hanya dipilih"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Gunakan nama yang berbeda secara internal"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Klik untuk menutup"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Silakan masukkan jumlah yang dapat disimpan oleh penyelenggara."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Masukkan jumlah untuk salah satu jenis tiket."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "diperlukan"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Zona waktu:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Waktu setempat Anda:"
|
||||
|
||||
|
||||
+2163
-1846
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||
"POT-Creation-Date: 2024-12-16 14:20+0000\n"
|
||||
"PO-Revision-Date: 2023-05-18 01:00+0000\n"
|
||||
"Last-Translator: M C <micasadmail@gmail.com>\n"
|
||||
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
@@ -652,40 +652,40 @@ msgid ""
|
||||
msgstr ""
|
||||
"Il colore scelto non ha un buon contrasto, per favore scegline uno più scuro."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:496
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:516
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:442
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:462
|
||||
msgid "Search query"
|
||||
msgstr "Chiave di ricerca"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:460
|
||||
msgid "All"
|
||||
msgstr "Tutto"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:515
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:461
|
||||
msgid "None"
|
||||
msgstr "Nessuno"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:519
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:465
|
||||
msgid "Selected only"
|
||||
msgstr "Solo i selezionati"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:862
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:808
|
||||
msgid "Enter page number between 1 and %(max)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:865
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:811
|
||||
msgid "Invalid page number."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1023
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:969
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Utilizza un nome diverso internamente"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1063
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1009
|
||||
msgid "Click to close"
|
||||
msgstr "Clicca per chiudere"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1138
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:1084
|
||||
msgid "You have unsaved changes!"
|
||||
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."
|
||||
msgstr "Inserisci l'importo che l'organizzatore può trattenere."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:454
|
||||
msgid "Please enter a quantity for one of the ticket types."
|
||||
msgstr "Inserisci la quantità per una tipologia di biglietto."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:506
|
||||
msgid "required"
|
||||
msgstr "richiesta"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:588
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:607
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:550
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:569
|
||||
msgid "Time zone:"
|
||||
msgstr "Fuso orario:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:598
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:560
|
||||
msgid "Your local time:"
|
||||
msgstr "Ora locale:"
|
||||
|
||||
|
||||
+9779
-7290
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user