forked from CGM_Public/pretix_original
Compare commits
80 Commits
hidden-pro
...
pretixscan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb3f3f5084 | ||
|
|
85edbe4837 | ||
|
|
6d12b3780c | ||
|
|
a99616b1e0 | ||
|
|
a5ba7440fe | ||
|
|
a02ea45dba | ||
|
|
c1e2fb36ba | ||
|
|
b67c684969 | ||
|
|
dc42dbb837 | ||
|
|
44ffc0685e | ||
|
|
a79a156a28 | ||
|
|
fb1f6c65af | ||
|
|
8d674965d1 | ||
|
|
020122b44f | ||
|
|
f55fff6495 | ||
|
|
08316129d3 | ||
|
|
a39563aa3e | ||
|
|
a3707a962b | ||
|
|
4bb8c3991e | ||
|
|
0d5c2f6329 | ||
|
|
17c0cfb395 | ||
|
|
e55f0cdf11 | ||
|
|
a2fbc376a5 | ||
|
|
be310a4e47 | ||
|
|
35037c79cc | ||
|
|
f8bb139651 | ||
|
|
77046136f2 | ||
|
|
53a0d62d93 | ||
|
|
d994fc674a | ||
|
|
f066ed01ff | ||
|
|
fb66434fc9 | ||
|
|
3f9269f6e5 | ||
|
|
2a30a1a039 | ||
|
|
846f20692d | ||
|
|
2eb5adb6c1 | ||
|
|
491753008d | ||
|
|
6d6cd3b7cf | ||
|
|
eaf6da7272 | ||
|
|
22ce7a388d | ||
|
|
e687eee9f1 | ||
|
|
e7baca952b | ||
|
|
eef713816e | ||
|
|
5a03033255 | ||
|
|
59daeba477 | ||
|
|
c1a4b8d343 | ||
|
|
0ac98f5127 | ||
|
|
55d423af18 | ||
|
|
285694955c | ||
|
|
2352f3b811 | ||
|
|
08bfe13dc3 | ||
|
|
ec522ed7e5 | ||
|
|
197ec84f05 | ||
|
|
42af8b1602 | ||
|
|
f6a4c5271e | ||
|
|
fb53beee2d | ||
|
|
ca1c387a41 | ||
|
|
5180b5e48b | ||
|
|
a5e94bf63f | ||
|
|
09ef7aac6e | ||
|
|
d90510a1bd | ||
|
|
48790e7743 | ||
|
|
cbeaf399df | ||
|
|
779a3698a8 | ||
|
|
a5e2caf438 | ||
|
|
ce79769293 | ||
|
|
9fbb8fa781 | ||
|
|
83c551c1ba | ||
|
|
328cd9bdc5 | ||
|
|
4ce7655958 | ||
|
|
bccc73f1dc | ||
|
|
5eeba88283 | ||
|
|
4c2fe9fc20 | ||
|
|
f2ba409b03 | ||
|
|
296c2b6e28 | ||
|
|
ab27bcca42 | ||
|
|
b0a365a099 | ||
|
|
97fc095d20 | ||
|
|
cfb1cd8fdb | ||
|
|
446cf68377 | ||
|
|
b727207e79 |
@@ -82,6 +82,11 @@ Example::
|
||||
Enables or disables obligatory usage of Two-Factor Authentication for users of the pretix backend.
|
||||
Defaults to ``False``
|
||||
|
||||
``trust_x_forwarded_for``
|
||||
Specifies whether the ``X-Forwarded-For`` header can be trusted. Only set to ``on`` if you have a reverse
|
||||
proxy that actively removes and re-adds the header to make sure the correct client IP is the first value.
|
||||
Defaults to ``off``.
|
||||
|
||||
|
||||
Locale settings
|
||||
---------------
|
||||
|
||||
@@ -207,7 +207,7 @@ Cart position endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/cartpositions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"item": 1,
|
||||
|
||||
@@ -131,7 +131,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/categories/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Tickets"},
|
||||
|
||||
@@ -209,7 +209,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/checkinlists/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "VIP entry",
|
||||
@@ -548,6 +548,8 @@ Order position endpoints
|
||||
you do not implement question handling in your user interface, you **must**
|
||||
set this to ``false``. In that case, questions will just be ignored. Defaults
|
||||
to ``true``.
|
||||
:<json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
|
||||
returned. Otherwise, canceled orders will return ``unpaid``.
|
||||
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
|
||||
:<json boolean force: Specifies that the check-in should succeed regardless of previous check-ins or required
|
||||
questions that have not been filled. Defaults to ``false``.
|
||||
@@ -576,6 +578,7 @@ Order position endpoints
|
||||
"nonce": "Pvrk50vUzQd0DhdpNRL4I4OcXsvg70uA",
|
||||
"datetime": null,
|
||||
"questions_supported": true,
|
||||
"canceled_supported": true,
|
||||
"answers": {
|
||||
"4": "XS"
|
||||
}
|
||||
@@ -659,7 +662,9 @@ Order position endpoints
|
||||
|
||||
Possible error reasons:
|
||||
|
||||
* ``unpaid`` - Ticket is not paid for or has been refunded
|
||||
* ``unpaid`` - Ticket is not paid for
|
||||
* ``canceled`` – Ticket is canceled or expired. This reason is only sent when your request sets
|
||||
``canceled_supported`` to ``true``, otherwise these orders return ``unpaid``.
|
||||
* ``already_redeemed`` - Ticket already has been redeemed
|
||||
* ``product`` - Tickets with this product may not be scanned at this device
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
@@ -285,7 +285,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/clone/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "Sample Conference"},
|
||||
@@ -362,7 +362,7 @@ Endpoints
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"plugins": [
|
||||
|
||||
@@ -134,7 +134,7 @@ Endpoints
|
||||
POST /api/v1/organizers/(organizer)/events/(event)/items/(item)/addons/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"addon_category": 1,
|
||||
|
||||
@@ -134,7 +134,7 @@ Endpoints
|
||||
POST /api/v1/organizers/(organizer)/events/(event)/items/(item)/bundles/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"bundled_item": 3,
|
||||
|
||||
@@ -152,7 +152,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/items/1/variations/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"value": {"en": "Student"},
|
||||
|
||||
@@ -72,6 +72,8 @@ generate_tickets boolean If ``false``, t
|
||||
non-admission or add-on product, regardless of event
|
||||
settings. If this is ``null``, regular ticketing
|
||||
rules apply.
|
||||
show_quota_left boolean Publicly show how many tickets are still available.
|
||||
If this is ``null``, the event default is used.
|
||||
has_variations boolean Shows whether or not this item has variations.
|
||||
variations list of objects A list with one object for each variation of this item.
|
||||
Can be empty. Only writable during creation,
|
||||
@@ -142,6 +144,10 @@ bundles list of objects Definition of b
|
||||
|
||||
The ``bundles`` and ``require_bundling`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The ``show_quota_left`` attribute has been added.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
@@ -207,6 +213,7 @@ Endpoints
|
||||
"checkin_attention": false,
|
||||
"has_variations": false,
|
||||
"generate_tickets": null,
|
||||
"show_quota_left": null,
|
||||
"require_approval": false,
|
||||
"require_bundling": false,
|
||||
"variations": [
|
||||
@@ -294,6 +301,7 @@ Endpoints
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"generate_tickets": null,
|
||||
"show_quota_left": null,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
@@ -342,7 +350,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/items/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
@@ -366,6 +374,7 @@ Endpoints
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
"generate_tickets": null,
|
||||
"show_quota_left": null,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"checkin_attention": false,
|
||||
@@ -427,6 +436,7 @@ Endpoints
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
"generate_tickets": null,
|
||||
"show_quota_left": null,
|
||||
"checkin_attention": false,
|
||||
"has_variations": true,
|
||||
"require_approval": false,
|
||||
@@ -515,6 +525,7 @@ Endpoints
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"generate_tickets": null,
|
||||
"show_quota_left": null,
|
||||
"allow_cancel": true,
|
||||
"min_per_order": null,
|
||||
"max_per_order": null,
|
||||
|
||||
@@ -698,8 +698,6 @@ Creating orders
|
||||
|
||||
Creates a new order.
|
||||
|
||||
.. warning:: This endpoint is considered **experimental**. It might change at any time without prior notice.
|
||||
|
||||
.. warning::
|
||||
|
||||
This endpoint is intended for advanced users. It is not designed to be used to build your own shop frontend,
|
||||
|
||||
@@ -54,11 +54,12 @@ dependency_question integer Internal ID of
|
||||
this attribute is set to the value given in
|
||||
``dependency_value``. This cannot be combined with
|
||||
``ask_during_checkin``.
|
||||
dependency_value string The value ``dependency_question`` needs to be set to.
|
||||
If ``dependency_question`` is set to a boolean
|
||||
question, this should be ``"true"`` or ``"false"``.
|
||||
Otherwise, it should be the ``identifier`` of a
|
||||
question option.
|
||||
dependency_values list of strings If ``dependency_question`` is set to a boolean
|
||||
question, this should be ``["True"]`` or ``["False"]``.
|
||||
Otherwise, it should be a list of ``identifier`` values
|
||||
of question options.
|
||||
dependency_value string An old version of ``dependency_values`` that only allows
|
||||
for one value. **Deprecated.**
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.12
|
||||
@@ -75,6 +76,10 @@ dependency_value string The value ``dep
|
||||
|
||||
The attribute ``hidden`` and the question type ``CC`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attribute ``dependency_values`` has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -120,6 +125,7 @@ Endpoints
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
@@ -188,6 +194,7 @@ Endpoints
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
@@ -228,7 +235,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/questions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"question": {"en": "T-Shirt size"},
|
||||
@@ -239,7 +246,7 @@ Endpoints
|
||||
"ask_during_checkin": false,
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"answer": {"en": "S"}
|
||||
@@ -274,6 +281,7 @@ Endpoints
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
@@ -346,6 +354,7 @@ Endpoints
|
||||
"hidden": false,
|
||||
"dependency_question": null,
|
||||
"dependency_value": null,
|
||||
"dependency_values": [],
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
|
||||
@@ -20,12 +20,22 @@ size integer The size of the
|
||||
items list of integers List of item IDs this quota acts on.
|
||||
variations list of integers List of item variation IDs this quota acts on.
|
||||
subevent integer ID of the date inside an event series this quota belongs to (or ``null``).
|
||||
close_when_sold_out boolean If ``true``, the quota will "close" as soon as it is
|
||||
sold out once. Even if tickets become available again,
|
||||
they will not be sold unless the quota is set to open
|
||||
again.
|
||||
closed boolean Whether the quota is currently closed (see above
|
||||
field).
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 1.10
|
||||
|
||||
The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
The attributes ``close_when_sold_out`` and ``closed`` have been added.
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
@@ -61,7 +71,9 @@ Endpoints
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -102,7 +114,9 @@ Endpoints
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -123,14 +137,16 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/quotas/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Ticket Quota",
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
@@ -147,7 +163,9 @@ Endpoints
|
||||
"size": 200,
|
||||
"items": [1, 2],
|
||||
"variations": [1, 4, 5, 7],
|
||||
"subevent": null
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/item to create a quota for
|
||||
@@ -200,7 +218,9 @@ Endpoints
|
||||
1,
|
||||
2
|
||||
],
|
||||
"subevent": null
|
||||
"subevent": null,
|
||||
"close_when_sold_out": false,
|
||||
"closed": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
|
||||
@@ -109,7 +109,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/seatingplans/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Main plan",
|
||||
|
||||
@@ -140,7 +140,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/subevents/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "First Sample Conference"},
|
||||
@@ -271,7 +271,7 @@ Endpoints
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/subevents/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": {"en": "New Subevent Name"},
|
||||
|
||||
@@ -137,7 +137,7 @@ Endpoints
|
||||
POST /api/v1/organizers/bigevents/webhooks/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": true,
|
||||
|
||||
@@ -20,7 +20,7 @@ Order events
|
||||
There are multiple signals that will be sent out in the ordering cycle:
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: validate_cart, validate_order, order_fee_calculation, order_paid, order_placed, order_canceled, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download
|
||||
:members: validate_cart, validate_cart_addons, validate_order, order_fee_calculation, order_paid, order_placed, order_canceled, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download, order_split
|
||||
|
||||
Frontend
|
||||
--------
|
||||
|
||||
@@ -65,9 +65,7 @@ Then, create the local database::
|
||||
python manage.py migrate
|
||||
|
||||
A first user with username ``admin@localhost`` and password ``admin`` will be automatically
|
||||
created. If you want to generate more test data, run::
|
||||
|
||||
python make_testdata.py
|
||||
created.
|
||||
|
||||
If you want to see pretix in a different language than English, you have to compile our language
|
||||
files::
|
||||
|
||||
@@ -85,8 +85,14 @@ Use case: Conference with workshops
|
||||
|
||||
When running a conference, you might also organize a number of workshops with smaller capacity. To be able to plan, it would be great to know which workshops an attendee plans to attend.
|
||||
|
||||
Option A: Questions
|
||||
"""""""""""""""""""
|
||||
|
||||
Your first and simplest option is to just create a multiple-choice question. This has the upside of making it easy for users to change their mind later on, but will not allow you to restrict the number of attendees signing up for a given workshop – or even charge extra for a given workshop.
|
||||
|
||||
Option B: Add-on products with fixed time slots
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
The usually better option is to go with add-on products. Let's take for example the following conference schedule, in which the lecture can be attended by anyone, but the workshops only have space for 20 persons each:
|
||||
|
||||
==================== =================================== ===================================
|
||||
@@ -117,6 +123,42 @@ Assuming you already created one or more products for your general conference ad
|
||||
|
||||
* One add-on configuration on your base product that allows users to choose between 0 and 2 products from the category "Workshops"
|
||||
|
||||
Option C: Add-on products with variable time slots
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
The above option only works if your conference uses fixed time slots and every workshop uses exactly one time slot. If
|
||||
your schedule looks like this, it's not going to work great:
|
||||
|
||||
+-------------+------------+-----------+
|
||||
| Time | Room A | Room B |
|
||||
+=============+============+===========+
|
||||
| 09:00-11:00 | Talk 1 | Long |
|
||||
+-------------+------------+ Workshop 1|
|
||||
| 11:00-13:00 | Talk 2 | |
|
||||
+-------------+------------+-----------+
|
||||
| 14:00-16:00 | Long | Talk 3 |
|
||||
+-------------+ workshop 2 +-----------+
|
||||
| 16:00-18:00 | | Talk 4 |
|
||||
+-------------+------------+-----------+
|
||||
|
||||
In this case, we recommend that you go to *Settings*, then *Plugins* and activate the plugin **Agenda constraints**.
|
||||
|
||||
Then, create a product (without variations) for every single part that should be bookable (talks 1-4 and long workshops
|
||||
1 and 2) as well as appropriate quotas for each of them.
|
||||
|
||||
All of these products should be part of the same category. In your base product (e.g. your conference ticket), you
|
||||
can then create an add-on product configuration allowing users to add products from this category.
|
||||
|
||||
If you edit these products, you will be able to enter the "Start date" and "End date" of the talk or workshop close
|
||||
to the bottom of the page. If you fill in these values, pretix will automatically ensure no overlapping talks are
|
||||
booked.
|
||||
|
||||
.. note::
|
||||
|
||||
This option is currently only available on pretix Hosted. If you are interested in using it with pretix Enterprise,
|
||||
please contact sales@pretix.eu.
|
||||
|
||||
|
||||
Use case: Discounted packages
|
||||
-----------------------------
|
||||
|
||||
|
||||
@@ -143,6 +143,11 @@ You can see an example here:
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
You can filter events by meta data attributes. You can create those attributes in your order profile and set their values in both event and series date
|
||||
settings. For example, if you set up a meta data property called "Promoted" that you set to "Yes" on some events, you can pass a filter like this::
|
||||
|
||||
<pretix-widget event="https://pretix.eu/demo/series/" style="list" filter="attr[Promoted]=Yes"></pretix-widget>
|
||||
|
||||
pretix Button
|
||||
-------------
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pretix.settings")
|
||||
|
||||
import django
|
||||
|
||||
django.setup()
|
||||
|
||||
from pretix.base.models import * # NOQA
|
||||
from django.utils.timezone import now
|
||||
|
||||
if Organizer.objects.exists():
|
||||
print("There already is data in your DB!")
|
||||
sys.exit(0)
|
||||
user = User.objects.get_or_create(
|
||||
email='admin@localhost',
|
||||
)[0]
|
||||
user.set_password('admin')
|
||||
user.save()
|
||||
organizer = Organizer.objects.create(
|
||||
name='BigEvents LLC', slug='bigevents'
|
||||
)
|
||||
year = now().year + 1
|
||||
event = Event.objects.create(
|
||||
organizer=organizer, name='Demo Conference {}'.format(year),
|
||||
slug=year, currency='EUR', live=True,
|
||||
date_from=datetime(year, 9, 4, 17, 0, 0),
|
||||
date_to=datetime(year, 9, 6, 17, 0, 0),
|
||||
)
|
||||
t = Team.objects.get_or_create(
|
||||
organizer=organizer, name='Admin Team',
|
||||
all_events=True, can_create_events=True, can_change_teams=True,
|
||||
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
|
||||
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
|
||||
)
|
||||
t[0].members.add(user)
|
||||
cat_tickets = ItemCategory.objects.create(
|
||||
event=event, name='Tickets'
|
||||
)
|
||||
cat_merch = ItemCategory.objects.create(
|
||||
event=event, name='Merchandise'
|
||||
)
|
||||
question = Question.objects.create(
|
||||
event=event, question='Age',
|
||||
type=Question.TYPE_NUMBER, required=False
|
||||
)
|
||||
tr19 = event.tax_rules.create(rate=19)
|
||||
item_ticket = Item.objects.create(
|
||||
event=event, category=cat_tickets, name='Ticket',
|
||||
default_price=23, tax_rule=tr19, admission=True
|
||||
)
|
||||
item_ticket.questions.add(question)
|
||||
item_shirt = Item.objects.create(
|
||||
event=event, category=cat_merch, name='T-Shirt',
|
||||
default_price=15, tax_rule=tr19
|
||||
)
|
||||
var_s = ItemVariation.objects.create(item=item_shirt, value='S')
|
||||
var_m = ItemVariation.objects.create(item=item_shirt, value='M')
|
||||
var_l = ItemVariation.objects.create(item=item_shirt, value='L')
|
||||
ticket_quota = Quota.objects.create(
|
||||
event=event, name='Ticket quota', size=400,
|
||||
)
|
||||
ticket_quota.items.add(item_ticket)
|
||||
ticket_shirts = Quota.objects.create(
|
||||
event=event, name='Shirt quota', size=200,
|
||||
)
|
||||
ticket_quota.items.add(item_shirt)
|
||||
ticket_quota.variations.add(var_s, var_m, var_l)
|
||||
@@ -127,7 +127,7 @@ class EventSerializer(I18nAwareModelSerializer):
|
||||
return value
|
||||
|
||||
def validate_seat_category_mapping(self, value):
|
||||
if value and (not self.instance or not self.instance.pk):
|
||||
if value and value['seat_category_mapping'] and (not self.instance or not self.instance.pk):
|
||||
raise ValidationError('You cannot specify seat category mappings on event creation.')
|
||||
item_cache = {i.pk: i for i in self.instance.items.all()}
|
||||
result = {}
|
||||
|
||||
@@ -118,7 +118,8 @@ class ItemSerializer(I18nAwareModelSerializer):
|
||||
'position', 'picture', 'available_from', 'available_until',
|
||||
'require_voucher', 'hide_without_voucher', 'allow_cancel', 'require_bundling',
|
||||
'min_per_order', 'max_per_order', 'checkin_attention', 'has_variations', 'variations',
|
||||
'addons', 'bundles', 'original_price', 'require_approval', 'generate_tickets')
|
||||
'addons', 'bundles', 'original_price', 'require_approval', 'generate_tickets',
|
||||
'show_quota_left')
|
||||
read_only_fields = ('has_variations', 'picture')
|
||||
|
||||
def get_serializer_context(self):
|
||||
@@ -200,15 +201,25 @@ class InlineQuestionOptionSerializer(I18nAwareModelSerializer):
|
||||
fields = ('id', 'identifier', 'answer', 'position')
|
||||
|
||||
|
||||
class LegacyDependencyValueField(serializers.CharField):
|
||||
|
||||
def to_representation(self, obj):
|
||||
return obj[0] if obj else None
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return [data] if data else []
|
||||
|
||||
|
||||
class QuestionSerializer(I18nAwareModelSerializer):
|
||||
options = InlineQuestionOptionSerializer(many=True, required=False)
|
||||
identifier = serializers.CharField(allow_null=True)
|
||||
dependency_value = LegacyDependencyValueField(source='dependency_values', required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = Question
|
||||
fields = ('id', 'question', 'type', 'required', 'items', 'options', 'position',
|
||||
'ask_during_checkin', 'identifier', 'dependency_question', 'dependency_value',
|
||||
'hidden')
|
||||
'ask_during_checkin', 'identifier', 'dependency_question', 'dependency_values',
|
||||
'hidden', 'dependency_value')
|
||||
|
||||
def validate_identifier(self, value):
|
||||
Question._clean_identifier(self.context['event'], value, self.instance)
|
||||
@@ -262,6 +273,7 @@ class QuestionSerializer(I18nAwareModelSerializer):
|
||||
def create(self, validated_data):
|
||||
options_data = validated_data.pop('options') if 'options' in validated_data else []
|
||||
items = validated_data.pop('items')
|
||||
|
||||
question = Question.objects.create(**validated_data)
|
||||
question.items.set(items)
|
||||
for opt_data in options_data:
|
||||
@@ -273,7 +285,7 @@ class QuotaSerializer(I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Quota
|
||||
fields = ('id', 'name', 'size', 'items', 'variations', 'subevent')
|
||||
fields = ('id', 'name', 'size', 'items', 'variations', 'subevent', 'closed', 'close_when_sold_out')
|
||||
|
||||
def validate(self, data):
|
||||
data = super().validate(data)
|
||||
|
||||
@@ -312,7 +312,6 @@ class OrderSerializer(I18nAwareModelSerializer):
|
||||
# Even though all fields that shouldn't be edited are marked as read_only in the serializer
|
||||
# (hopefully), we'll be extra careful here and be explicit about the model fields we update.
|
||||
update_fields = ['comment', 'checkin_attention', 'email', 'locale']
|
||||
print(validated_data)
|
||||
|
||||
if 'invoice_address' in validated_data:
|
||||
iadata = validated_data.pop('invoice_address')
|
||||
@@ -598,6 +597,9 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
||||
{'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]}
|
||||
for p in data
|
||||
]
|
||||
else:
|
||||
for i, p in enumerate(data):
|
||||
p['positionid'] = i + 1
|
||||
|
||||
if any(errs):
|
||||
raise ValidationError(errs)
|
||||
|
||||
@@ -93,6 +93,7 @@ class CheckinListViewSet(viewsets.ModelViewSet):
|
||||
)
|
||||
if not clist.all_products:
|
||||
pqs = pqs.filter(item__in=clist.limit_products.values_list('id', flat=True))
|
||||
cqs = cqs.filter(position__item__in=clist.limit_products.values_list('id', flat=True))
|
||||
|
||||
ev = clist.subevent or clist.event
|
||||
response = {
|
||||
@@ -280,6 +281,7 @@ class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
nonce=nonce,
|
||||
datetime=dt,
|
||||
questions_supported=self.request.data.get('questions_supported', True),
|
||||
canceled_supported=self.request.data.get('canceled_supported', False),
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
)
|
||||
|
||||
@@ -473,6 +473,19 @@ class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
# This costs us a few cycles on save, but avoids thousands of lines in our log.
|
||||
return
|
||||
|
||||
if original_data['closed'] is True and serializer.instance.closed is False:
|
||||
serializer.instance.log_action(
|
||||
'pretix.event.quota.opened',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
)
|
||||
elif original_data['closed'] is False and serializer.instance.closed is True:
|
||||
serializer.instance.log_action(
|
||||
'pretix.event.quota.closed',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
)
|
||||
|
||||
serializer.instance.log_action(
|
||||
'pretix.event.quota.changed',
|
||||
user=self.request.user,
|
||||
|
||||
@@ -71,6 +71,8 @@ class BaseExporter:
|
||||
|
||||
:type form_data: dict
|
||||
:param form_data: The form data of the export details form
|
||||
:param output_file: You can optionally accept a parameter that will be given a file handle to write the
|
||||
output to. In this case, you can return None instead of the file content.
|
||||
|
||||
Note: If you use a ``ModelChoiceField`` (or a ``ModelMultipleChoiceField``), the
|
||||
``form_data`` will not contain the model instance but only it's primary key (or
|
||||
@@ -111,14 +113,20 @@ class ListExporter(BaseExporter):
|
||||
def get_filename(self):
|
||||
return 'export.csv'
|
||||
|
||||
def _render_csv(self, form_data, **kwargs):
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output, **kwargs)
|
||||
for line in self.iterate_list(form_data):
|
||||
writer.writerow(line)
|
||||
return self.get_filename() + '.csv', 'text/csv', output.getvalue().encode("utf-8")
|
||||
def _render_csv(self, form_data, output_file=None, **kwargs):
|
||||
if output_file:
|
||||
writer = csv.writer(output_file, **kwargs)
|
||||
for line in self.iterate_list(form_data):
|
||||
writer.writerow(line)
|
||||
return self.get_filename() + '.csv', 'text/csv', None
|
||||
else:
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output, **kwargs)
|
||||
for line in self.iterate_list(form_data):
|
||||
writer.writerow(line)
|
||||
return self.get_filename() + '.csv', 'text/csv', output.getvalue().encode("utf-8")
|
||||
|
||||
def _render_xlsx(self, form_data):
|
||||
def _render_xlsx(self, form_data, output_file=None):
|
||||
wb = Workbook()
|
||||
ws = wb.get_active_sheet()
|
||||
try:
|
||||
@@ -129,20 +137,24 @@ class ListExporter(BaseExporter):
|
||||
for j, val in enumerate(line):
|
||||
ws.cell(row=i + 1, column=j + 1).value = str(val) if not isinstance(val, KNOWN_TYPES) else val
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx') as f:
|
||||
wb.save(f.name)
|
||||
f.seek(0)
|
||||
return self.get_filename() + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', f.read()
|
||||
if output_file:
|
||||
wb.save(output_file)
|
||||
return self.get_filename() + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', None
|
||||
else:
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx') as f:
|
||||
wb.save(f.name)
|
||||
f.seek(0)
|
||||
return self.get_filename() + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', f.read()
|
||||
|
||||
def render(self, form_data: dict) -> Tuple[str, str, bytes]:
|
||||
def render(self, form_data: dict, output_file=None) -> Tuple[str, str, bytes]:
|
||||
if form_data.get('_format') == 'xlsx':
|
||||
return self._render_xlsx(form_data)
|
||||
return self._render_xlsx(form_data, output_file=output_file)
|
||||
elif form_data.get('_format') == 'default':
|
||||
return self._render_csv(form_data, quoting=csv.QUOTE_NONNUMERIC, delimiter=',')
|
||||
return self._render_csv(form_data, quoting=csv.QUOTE_NONNUMERIC, delimiter=',', output_file=output_file)
|
||||
elif form_data.get('_format') == 'csv-excel':
|
||||
return self._render_csv(form_data, dialect='excel')
|
||||
return self._render_csv(form_data, dialect='excel', output_file=output_file)
|
||||
elif form_data.get('_format') == 'semicolon':
|
||||
return self._render_csv(form_data, dialect='excel', delimiter=';')
|
||||
return self._render_csv(form_data, dialect='excel', delimiter=';', output_file=output_file)
|
||||
|
||||
|
||||
class MultiSheetListExporter(ListExporter):
|
||||
@@ -180,14 +192,20 @@ class MultiSheetListExporter(ListExporter):
|
||||
def iterate_sheet(self, form_data, sheet):
|
||||
raise NotImplementedError() # noqa
|
||||
|
||||
def _render_sheet_csv(self, form_data, sheet, **kwargs):
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output, **kwargs)
|
||||
for line in self.iterate_sheet(form_data, sheet):
|
||||
writer.writerow(line)
|
||||
return self.get_filename() + '.csv', 'text/csv', output.getvalue().encode("utf-8")
|
||||
def _render_sheet_csv(self, form_data, sheet, output_file=None, **kwargs):
|
||||
if output_file:
|
||||
writer = csv.writer(output_file, **kwargs)
|
||||
for line in self.iterate_sheet(form_data, sheet):
|
||||
writer.writerow(line)
|
||||
return self.get_filename() + '.csv', 'text/csv', None
|
||||
else:
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output, **kwargs)
|
||||
for line in self.iterate_sheet(form_data, sheet):
|
||||
writer.writerow(line)
|
||||
return self.get_filename() + '.csv', 'text/csv', output.getvalue().encode("utf-8")
|
||||
|
||||
def _render_xlsx(self, form_data):
|
||||
def _render_xlsx(self, form_data, output_file=None):
|
||||
wb = Workbook()
|
||||
ws = wb.get_active_sheet()
|
||||
wb.remove(ws)
|
||||
@@ -197,19 +215,24 @@ class MultiSheetListExporter(ListExporter):
|
||||
for j, val in enumerate(line):
|
||||
ws.cell(row=i + 1, column=j + 1).value = str(val) if not isinstance(val, KNOWN_TYPES) else val
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx') as f:
|
||||
wb.save(f.name)
|
||||
f.seek(0)
|
||||
return self.get_filename() + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', f.read()
|
||||
if output_file:
|
||||
wb.save(output_file)
|
||||
return self.get_filename() + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', None
|
||||
else:
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx') as f:
|
||||
wb.save(f.name)
|
||||
f.seek(0)
|
||||
return self.get_filename() + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', f.read()
|
||||
|
||||
def render(self, form_data: dict) -> Tuple[str, str, bytes]:
|
||||
def render(self, form_data: dict, output_file=None) -> Tuple[str, str, bytes]:
|
||||
if form_data.get('_format') == 'xlsx':
|
||||
return self._render_xlsx(form_data)
|
||||
return self._render_xlsx(form_data, output_file=output_file)
|
||||
elif ':' in form_data.get('_format'):
|
||||
sheet, f = form_data.get('_format').split(':')
|
||||
if f == 'default':
|
||||
return self._render_sheet_csv(form_data, sheet, quoting=csv.QUOTE_NONNUMERIC, delimiter=',')
|
||||
return self._render_sheet_csv(form_data, sheet, quoting=csv.QUOTE_NONNUMERIC, delimiter=',',
|
||||
output_file=output_file)
|
||||
elif f == 'excel':
|
||||
return self._render_sheet_csv(form_data, sheet, dialect='excel')
|
||||
return self._render_sheet_csv(form_data, sheet, dialect='excel', output_file=output_file)
|
||||
elif f == 'semicolon':
|
||||
return self._render_sheet_csv(form_data, sheet, dialect='excel', delimiter=';')
|
||||
return self._render_sheet_csv(form_data, sheet, dialect='excel', delimiter=';', output_file=output_file)
|
||||
|
||||
@@ -20,7 +20,7 @@ class InvoiceExporter(BaseExporter):
|
||||
identifier = 'invoices'
|
||||
verbose_name = _('All invoices')
|
||||
|
||||
def render(self, form_data: dict):
|
||||
def render(self, form_data: dict, output_file=None):
|
||||
qs = self.event.invoices.filter(shredded=False)
|
||||
|
||||
if form_data.get('payment_provider'):
|
||||
@@ -47,7 +47,7 @@ class InvoiceExporter(BaseExporter):
|
||||
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
any = False
|
||||
with ZipFile(os.path.join(d, 'tmp.zip'), 'w') as zipf:
|
||||
with ZipFile(output_file or os.path.join(d, 'tmp.zip'), 'w') as zipf:
|
||||
for i in qs:
|
||||
try:
|
||||
if not i.file:
|
||||
@@ -68,8 +68,11 @@ class InvoiceExporter(BaseExporter):
|
||||
if not any:
|
||||
return None
|
||||
|
||||
with open(os.path.join(d, 'tmp.zip'), 'rb') as zipf:
|
||||
return '{}_invoices.zip'.format(self.event.slug), 'application/zip', zipf.read()
|
||||
if output_file:
|
||||
return '{}_invoices.zip'.format(self.event.slug), 'application/zip', None
|
||||
else:
|
||||
with open(os.path.join(d, 'tmp.zip'), 'rb') as zipf:
|
||||
return '{}_invoices.zip'.format(self.event.slug), 'application/zip', zipf.read()
|
||||
|
||||
@property
|
||||
def export_form_fields(self):
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
from decimal import Decimal
|
||||
from urllib.error import HTTPError
|
||||
|
||||
import dateutil.parser
|
||||
import pytz
|
||||
@@ -9,6 +11,8 @@ import vat_moss.id
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import QuerySet
|
||||
from django.forms import Select
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import get_language, ugettext_lazy as _
|
||||
@@ -21,9 +25,10 @@ from pretix.base.forms.widgets import (
|
||||
)
|
||||
from pretix.base.models import InvoiceAddress, Question, QuestionOption
|
||||
from pretix.base.models.tax import EU_COUNTRIES
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.control.forms import SplitDateTimeField
|
||||
from pretix.helpers.escapejson import escapejson_attr
|
||||
from pretix.helpers.i18n import get_format_without_seconds
|
||||
from pretix.presale.signals import question_form_fields
|
||||
|
||||
@@ -33,14 +38,18 @@ logger = logging.getLogger(__name__)
|
||||
class NamePartsWidget(forms.MultiWidget):
|
||||
widget = forms.TextInput
|
||||
|
||||
def __init__(self, scheme: dict, field: forms.Field, attrs=None):
|
||||
def __init__(self, scheme: dict, field: forms.Field, attrs=None, titles: list=None):
|
||||
widgets = []
|
||||
self.scheme = scheme
|
||||
self.field = field
|
||||
self.titles = titles
|
||||
for fname, label, size in self.scheme['fields']:
|
||||
a = copy.copy(attrs) or {}
|
||||
a['data-fname'] = fname
|
||||
widgets.append(self.widget(attrs=a))
|
||||
if fname == 'title' and self.titles:
|
||||
widgets.append(Select(attrs=a, choices=[('', '')] + [(d, d) for d in self.titles[1]]))
|
||||
else:
|
||||
widgets.append(self.widget(attrs=a))
|
||||
super().__init__(widgets, attrs)
|
||||
|
||||
def decompress(self, value):
|
||||
@@ -99,19 +108,34 @@ class NamePartsFormField(forms.MultiValueField):
|
||||
'max_length': kwargs.pop('max_length', None),
|
||||
}
|
||||
self.scheme_name = kwargs.pop('scheme')
|
||||
self.titles = kwargs.pop('titles')
|
||||
self.scheme = PERSON_NAME_SCHEMES.get(self.scheme_name)
|
||||
if self.titles:
|
||||
self.scheme_titles = PERSON_NAME_TITLE_GROUPS.get(self.titles)
|
||||
else:
|
||||
self.scheme_titles = None
|
||||
self.one_required = kwargs.get('required', True)
|
||||
require_all_fields = kwargs.pop('require_all_fields', False)
|
||||
kwargs['required'] = False
|
||||
kwargs['widget'] = (kwargs.get('widget') or self.widget)(
|
||||
scheme=self.scheme, field=self, **kwargs.pop('widget_kwargs', {})
|
||||
scheme=self.scheme, titles=self.scheme_titles, field=self, **kwargs.pop('widget_kwargs', {})
|
||||
)
|
||||
defaults.update(**kwargs)
|
||||
for fname, label, size in self.scheme['fields']:
|
||||
defaults['label'] = label
|
||||
field = forms.CharField(**defaults)
|
||||
field.part_name = fname
|
||||
fields.append(field)
|
||||
if fname == 'title' and self.scheme_titles:
|
||||
d = dict(defaults)
|
||||
d.pop('max_length', None)
|
||||
field = forms.ChoiceField(
|
||||
**d,
|
||||
choices=[('', '')] + [(d, d) for d in self.scheme_titles[1]]
|
||||
)
|
||||
field.part_name = fname
|
||||
fields.append(field)
|
||||
else:
|
||||
field = forms.CharField(**defaults)
|
||||
field.part_name = fname
|
||||
fields.append(field)
|
||||
super().__init__(
|
||||
fields=fields, require_all_fields=False, *args, **kwargs
|
||||
)
|
||||
@@ -156,6 +180,7 @@ class BaseQuestionsForm(forms.Form):
|
||||
max_length=255,
|
||||
required=event.settings.attendee_names_required,
|
||||
scheme=event.settings.name_scheme,
|
||||
titles=event.settings.name_scheme_titles,
|
||||
label=_('Attendee name'),
|
||||
initial=(cartpos.attendee_name_parts if cartpos else orderpos.attendee_name_parts),
|
||||
)
|
||||
@@ -277,7 +302,7 @@ class BaseQuestionsForm(forms.Form):
|
||||
|
||||
if q.dependency_question_id:
|
||||
field.widget.attrs['data-question-dependency'] = q.dependency_question_id
|
||||
field.widget.attrs['data-question-dependency-value'] = q.dependency_value
|
||||
field.widget.attrs['data-question-dependency-values'] = escapejson_attr(json.dumps(q.dependency_values))
|
||||
if q.type != 'M':
|
||||
field.widget.attrs['required'] = q.required and not self.all_optional
|
||||
field._required = q.required and not self.all_optional
|
||||
@@ -298,26 +323,24 @@ class BaseQuestionsForm(forms.Form):
|
||||
|
||||
question_cache = {f.question.pk: f.question for f in self.fields.values() if getattr(f, 'question', None)}
|
||||
|
||||
def question_is_visible(parentid, qval):
|
||||
def question_is_visible(parentid, qvals):
|
||||
parentq = question_cache[parentid]
|
||||
if parentq.dependency_question_id and not question_is_visible(parentq.dependency_question_id, parentq.dependency_value):
|
||||
if parentq.dependency_question_id and not question_is_visible(parentq.dependency_question_id, parentq.dependency_values):
|
||||
return False
|
||||
if 'question_%d' % parentid not in d:
|
||||
return False
|
||||
dval = d.get('question_%d' % parentid)
|
||||
if qval == 'True':
|
||||
return dval
|
||||
elif qval == 'False':
|
||||
return not dval
|
||||
elif isinstance(dval, QuestionOption):
|
||||
return dval.identifier == qval
|
||||
else:
|
||||
return qval in [o.identifier for o in dval]
|
||||
return (
|
||||
('True' in qvals and dval)
|
||||
or ('False' in qvals and not dval)
|
||||
or (isinstance(dval, QuestionOption) and dval.identifier in qvals)
|
||||
or (isinstance(dval, (list, QuerySet)) and any(qval in [o.identifier for o in dval] 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_value))
|
||||
(not q.dependency_question_id or question_is_visible(q.dependency_question_id, q.dependency_values))
|
||||
)
|
||||
|
||||
if not self.all_optional:
|
||||
@@ -398,6 +421,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
max_length=255,
|
||||
required=event.settings.invoice_name_required and not self.all_optional,
|
||||
scheme=event.settings.name_scheme,
|
||||
titles=event.settings.name_scheme_titles,
|
||||
label=_('Name'),
|
||||
initial=(self.instance.name_parts if self.instance else self.instance.name_parts),
|
||||
)
|
||||
@@ -451,7 +475,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
'your country is currently not available. We will therefore '
|
||||
'need to charge VAT on your invoice. You can get the tax amount '
|
||||
'back via the VAT reimbursement process.'))
|
||||
except vat_moss.errors.WebServiceError:
|
||||
except (vat_moss.errors.WebServiceError, HTTPError):
|
||||
logger.exception('VAT ID checking failed for country {}'.format(data.get('country')))
|
||||
self.instance.vat_id_validated = False
|
||||
if self.request and self.vat_warning:
|
||||
|
||||
58
src/pretix/base/management/commands/export.py
Normal file
58
src/pretix/base/management/commands/export.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.timezone import override
|
||||
from django_scopes import scope
|
||||
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import Event, Organizer
|
||||
from pretix.base.signals import register_data_exporters
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Run an exporter to get data out of pretix"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('organizer_slug', nargs=1, type=str)
|
||||
parser.add_argument('event_slug', nargs=1, type=str)
|
||||
parser.add_argument('export_provider', nargs=1, type=str)
|
||||
parser.add_argument('output_file', nargs=1, type=str)
|
||||
parser.add_argument('--parameters', action='store', type=str, help='JSON-formatted parameters')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
try:
|
||||
o = Organizer.objects.get(slug=options['organizer_slug'][0])
|
||||
except Organizer.DoesNotExist:
|
||||
self.stderr.write(self.style.ERROR('Organizer not found.'))
|
||||
sys.exit(1)
|
||||
|
||||
with scope(organizer=o):
|
||||
try:
|
||||
e = o.events.get(slug=options['event_slug'][0])
|
||||
except Event.DoesNotExist:
|
||||
self.stderr.write(self.style.ERROR('Event not found.'))
|
||||
sys.exit(1)
|
||||
|
||||
with language(e.settings.locale), override(e.settings.timezone):
|
||||
responses = register_data_exporters.send(e)
|
||||
for receiver, response in responses:
|
||||
ex = response(e)
|
||||
if ex.identifier == options['export_provider'][0]:
|
||||
params = json.loads(options.get('parameters') or '{}')
|
||||
with open(options['output_file'][0], 'wb') as f:
|
||||
try:
|
||||
ex.render(form_data=params, output_file=f)
|
||||
except TypeError:
|
||||
self.stderr.write(self.style.WARNING(
|
||||
'Provider does not support direct file writing, need to buffer export in memory.'))
|
||||
d = ex.render(form_data=params)
|
||||
if d is None:
|
||||
self.stderr.write(self.style.ERROR('Empty export.'))
|
||||
sys.exit(2)
|
||||
f.write(d[2])
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
self.stderr.write(self.style.ERROR('Export provider not found.'))
|
||||
sys.exit(1)
|
||||
@@ -2,7 +2,7 @@
|
||||
Django tries to be helpful by suggesting to run "makemigrations" in red font on every "migrate"
|
||||
run when there are things we have no migrations for. Usually, this is intended, and running
|
||||
"makemigrations" can really screw up the environment of a user, so we want to prevent novice
|
||||
users from doing that by going really dirty and fitlering it from the output.
|
||||
users from doing that by going really dirty and filtering it from the output.
|
||||
"""
|
||||
import sys
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class Command(BaseCommand):
|
||||
flags = parser.parse_known_args(sys.argv[2:])[1]
|
||||
if "--override" in flags:
|
||||
with scopes_disabled():
|
||||
return call_command("shell", *args, **options)
|
||||
return call_command("shell_plus", *args, **options)
|
||||
|
||||
lookups = {}
|
||||
for flag in flags:
|
||||
@@ -36,4 +36,4 @@ class Command(BaseCommand):
|
||||
for app_name, app_value in lookups.items()
|
||||
}
|
||||
with scope(**scope_options):
|
||||
return call_command("shell", *args, **options)
|
||||
return call_command("shell_plus", *args, **options)
|
||||
|
||||
18
src/pretix/base/migrations/0126_item_show_quota_left.py
Normal file
18
src/pretix/base/migrations/0126_item_show_quota_left.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.2.1 on 2019-07-10 13:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0125_voucher_show_hidden_items'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='show_quota_left',
|
||||
field=models.NullBooleanField(),
|
||||
),
|
||||
]
|
||||
25
src/pretix/base/migrations/0127_auto_20190711_0705.py
Normal file
25
src/pretix/base/migrations/0127_auto_20190711_0705.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 2.2.1 on 2019-07-11 07:05
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
import pretix.base.models.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0126_item_show_quota_left'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='question',
|
||||
old_name='dependency_value',
|
||||
new_name='dependency_values',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='question',
|
||||
name='dependency_values',
|
||||
field=pretix.base.models.fields.MultiStringField(default=['']),
|
||||
),
|
||||
]
|
||||
26
src/pretix/base/migrations/0128_auto_20190715_1510.py
Normal file
26
src/pretix/base/migrations/0128_auto_20190715_1510.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 2.2.1 on 2019-07-15 15:10
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
import pretix.base.models.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0127_auto_20190711_0705'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='quota',
|
||||
name='close_when_sold_out',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='quota',
|
||||
name='closed',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -86,7 +86,7 @@ class LoggingMixin:
|
||||
if (sensitivekey in k) and v:
|
||||
data[k] = "********"
|
||||
|
||||
logentry.data = json.dumps(data, cls=CustomJSONEncoder)
|
||||
logentry.data = json.dumps(data, cls=CustomJSONEncoder, sort_keys=True)
|
||||
elif data:
|
||||
raise TypeError("You should only supply dictionaries as log data.")
|
||||
if save:
|
||||
|
||||
@@ -100,14 +100,14 @@ class EventMixin:
|
||||
"DATETIME_FORMAT" if self.settings.show_times else "DATE_FORMAT"
|
||||
)
|
||||
|
||||
def get_date_range_display(self, tz=None) -> str:
|
||||
def get_date_range_display(self, tz=None, force_show_end=False) -> str:
|
||||
"""
|
||||
Returns a formatted string containing the start date and the end date
|
||||
of the event with respect to the current locale and to the ``show_times`` and
|
||||
``show_date_to`` settings.
|
||||
"""
|
||||
tz = tz or self.timezone
|
||||
if not self.settings.show_date_to or not self.date_to:
|
||||
if (not self.settings.show_date_to and not force_show_end) or not self.date_to:
|
||||
return _date(self.date_from.astimezone(tz), "DATE_FORMAT")
|
||||
return daterange(self.date_from.astimezone(tz), self.date_to.astimezone(tz))
|
||||
|
||||
@@ -518,6 +518,11 @@ class Event(EventMixin, LoggedModel):
|
||||
vars = list(q.variations.all())
|
||||
q.pk = None
|
||||
q.event = self
|
||||
q.cached_availability_state = None
|
||||
q.cached_availability_number = None
|
||||
q.cached_availability_paid_orders = None
|
||||
q.cached_availability_time = None
|
||||
q.closed = False
|
||||
q.save()
|
||||
for i in items:
|
||||
if i.pk in item_map:
|
||||
@@ -710,8 +715,12 @@ class Event(EventMixin, LoggedModel):
|
||||
@property
|
||||
def meta_data(self):
|
||||
data = {p.name: p.default for p in self.organizer.meta_properties.all()}
|
||||
data.update({v.property.name: v.value for v in self.meta_values.select_related('property').all()})
|
||||
return data
|
||||
if hasattr(self, 'meta_values_cached'):
|
||||
data.update({v.property.name: v.value for v in self.meta_values_cached})
|
||||
else:
|
||||
data.update({v.property.name: v.value for v in self.meta_values.select_related('property').all()})
|
||||
|
||||
return OrderedDict((k, v) for k, v in sorted(data.items(), key=lambda k: k[0]))
|
||||
|
||||
@property
|
||||
def has_payment_provider(self):
|
||||
|
||||
@@ -22,6 +22,7 @@ from i18nfield.fields import I18nCharField, I18nTextField
|
||||
|
||||
from pretix.base.models import fields
|
||||
from pretix.base.models.base import LoggedModel
|
||||
from pretix.base.models.fields import MultiStringField
|
||||
from pretix.base.models.tax import TaxedPrice
|
||||
from pretix.base.signals import quota_availability
|
||||
|
||||
@@ -168,15 +169,18 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False):
|
||||
)
|
||||
if not allow_addons:
|
||||
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
|
||||
qs = qs.filter(q)
|
||||
|
||||
vouchq = Q(hide_without_voucher=False)
|
||||
if voucher and voucher.show_hidden_items:
|
||||
if voucher:
|
||||
if voucher.item_id:
|
||||
vouchq = Q(pk=voucher.item_id)
|
||||
q &= Q(pk=voucher.item_id)
|
||||
elif voucher.quota_id:
|
||||
vouchq = Q(quotas__in=[voucher.quota_id])
|
||||
return qs.filter(vouchq)
|
||||
q &= Q(quotas__in=[voucher.quota_id])
|
||||
else:
|
||||
return qs.none()
|
||||
if not voucher or not voucher.show_hidden_items:
|
||||
q &= Q(hide_without_voucher=False)
|
||||
|
||||
return qs.filter(q)
|
||||
|
||||
|
||||
class ItemQuerySet(models.QuerySet):
|
||||
@@ -307,6 +311,11 @@ class Item(LoggedModel):
|
||||
verbose_name=_("Generate tickets"),
|
||||
blank=True, null=True,
|
||||
)
|
||||
show_quota_left = models.NullBooleanField(
|
||||
verbose_name=_("Show number of tickets left"),
|
||||
help_text=_("Publicly show how many tickets are still available."),
|
||||
blank=True, null=True,
|
||||
)
|
||||
position = models.IntegerField(
|
||||
default=0
|
||||
)
|
||||
@@ -405,10 +414,17 @@ class Item(LoggedModel):
|
||||
self.event.cache.clear()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.vouchers.update(item=None, variation=None, quota=None)
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
@property
|
||||
def do_show_quota_left(self):
|
||||
if self.show_quota_left is None:
|
||||
return self.event.settings.show_quota_left
|
||||
return self.show_quota_left
|
||||
|
||||
def tax(self, price=None, base_price_is='auto', currency=None, include_bundled=False):
|
||||
price = price if price is not None else self.default_price
|
||||
|
||||
@@ -643,6 +659,7 @@ class ItemVariation(models.Model):
|
||||
return t
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.vouchers.update(item=None, variation=None, quota=None)
|
||||
super().delete(*args, **kwargs)
|
||||
if self.item:
|
||||
self.item.event.cache.clear()
|
||||
@@ -918,8 +935,8 @@ class Question(LoggedModel):
|
||||
:type identifier: str
|
||||
:param dependency_question: This question will only show up if the referenced question is set to `dependency_value`.
|
||||
:type dependency_question: Question
|
||||
:param dependency_value: The value that `dependency_question` needs to be set to for this question to be applicable.
|
||||
:type dependency_value: str
|
||||
:param dependency_values: The values that `dependency_question` needs to be set to for this question to be applicable.
|
||||
:type dependency_values: list[str]
|
||||
"""
|
||||
TYPE_NUMBER = "N"
|
||||
TYPE_STRING = "S"
|
||||
@@ -999,7 +1016,7 @@ class Question(LoggedModel):
|
||||
dependency_question = models.ForeignKey(
|
||||
'Question', null=True, blank=True, on_delete=models.SET_NULL, related_name='dependent_questions'
|
||||
)
|
||||
dependency_value = models.TextField(null=True, blank=True)
|
||||
dependency_values = MultiStringField(default=[])
|
||||
|
||||
objects = ScopedManager(organizer='event__organizer')
|
||||
|
||||
@@ -1252,6 +1269,15 @@ class Quota(LoggedModel):
|
||||
cached_availability_paid_orders = models.PositiveIntegerField(null=True, blank=True)
|
||||
cached_availability_time = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
close_when_sold_out = models.BooleanField(
|
||||
verbose_name=_('Close this quota permanently once it is sold out'),
|
||||
help_text=_('If you enable this, when the quota is sold out once, no more tickets will be sold, '
|
||||
'even if tickets become available again through cancellations or expiring orders. Of course, '
|
||||
'you can always re-open it manually.'),
|
||||
default=False
|
||||
)
|
||||
closed = models.BooleanField(default=False)
|
||||
|
||||
objects = ScopedManager(organizer='event__organizer')
|
||||
|
||||
class Meta:
|
||||
@@ -1263,6 +1289,7 @@ class Quota(LoggedModel):
|
||||
return self.name
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.vouchers.update(item=None, variation=None, quota=None)
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
@@ -1316,6 +1343,11 @@ class Quota(LoggedModel):
|
||||
count_waitinglist=count_waitinglist):
|
||||
res = resp
|
||||
|
||||
if res[0] <= Quota.AVAILABILITY_ORDERED and self.close_when_sold_out and not self.closed:
|
||||
self.closed = True
|
||||
self.save(update_fields=['closed'])
|
||||
self.log_action('pretix.event.quota.closed')
|
||||
|
||||
self.event.cache.delete('item_quota_cache')
|
||||
rewrite_cache = count_waitinglist and (
|
||||
not self.cache_is_hot(now_dt) or res[0] > self.cached_availability_state
|
||||
@@ -1340,8 +1372,11 @@ class Quota(LoggedModel):
|
||||
_cache['_count_waitinglist'] = count_waitinglist
|
||||
return res
|
||||
|
||||
def _availability(self, now_dt: datetime=None, count_waitinglist=True):
|
||||
def _availability(self, now_dt: datetime=None, count_waitinglist=True, ignore_closed=False):
|
||||
now_dt = now_dt or now()
|
||||
if self.closed and not ignore_closed:
|
||||
return Quota.AVAILABILITY_ORDERED, 0
|
||||
|
||||
size_left = self.size
|
||||
if size_left is None:
|
||||
return Quota.AVAILABILITY_OK, None
|
||||
|
||||
@@ -870,6 +870,10 @@ class QuestionAnswer(models.Model):
|
||||
return url
|
||||
return ""
|
||||
|
||||
@property
|
||||
def is_image(self):
|
||||
return any(self.file.name.endswith(e) for e in ('.jpg', '.png', '.gif', '.tiff', '.bmp', '.jpeg'))
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
return self.file.name.split('.', 1)[-1]
|
||||
@@ -1038,18 +1042,17 @@ class AbstractPosition(models.Model):
|
||||
q.pk: q for q in questions
|
||||
}
|
||||
|
||||
def question_is_visible(parentid, qval):
|
||||
def question_is_visible(parentid, qvals):
|
||||
parentq = question_cache[parentid]
|
||||
if parentq.dependency_question_id and not question_is_visible(parentq.dependency_question_id, parentq.dependency_value):
|
||||
if parentq.dependency_question_id and not question_is_visible(parentq.dependency_question_id, parentq.dependency_values):
|
||||
return False
|
||||
if parentid not in self.answ:
|
||||
return False
|
||||
if qval == 'True':
|
||||
return self.answ[parentid].answer == 'True'
|
||||
elif qval == 'False':
|
||||
return self.answ[parentid].answer == 'False'
|
||||
else:
|
||||
return qval in [o.identifier for o in self.answ[parentid].options.all()]
|
||||
return (
|
||||
('True' in qvals and self.answ[parentid].answer == 'True')
|
||||
or ('False' in qvals and self.answ[parentid].answer == 'False')
|
||||
or (any(qval in [o.identifier for o in self.answ[parentid].options.all()] for qval in qvals))
|
||||
)
|
||||
|
||||
self.questions = []
|
||||
for q in questions:
|
||||
@@ -1058,7 +1061,7 @@ class AbstractPosition(models.Model):
|
||||
q.answer.question = q # cache object
|
||||
else:
|
||||
q.answer = ""
|
||||
if not q.dependency_question_id or question_is_visible(q.dependency_question_id, q.dependency_value):
|
||||
if not q.dependency_question_id or question_is_visible(q.dependency_question_id, q.dependency_values):
|
||||
self.questions.append(q)
|
||||
|
||||
@property
|
||||
@@ -1185,7 +1188,7 @@ class OrderPayment(models.Model):
|
||||
|
||||
@info_data.setter
|
||||
def info_data(self, d):
|
||||
self.info = json.dumps(d)
|
||||
self.info = json.dumps(d, sort_keys=True)
|
||||
|
||||
@cached_property
|
||||
def payment_provider(self):
|
||||
@@ -1543,7 +1546,7 @@ class OrderRefund(models.Model):
|
||||
|
||||
@info_data.setter
|
||||
def info_data(self, d):
|
||||
self.info = json.dumps(d)
|
||||
self.info = json.dumps(d, sort_keys=True)
|
||||
|
||||
@cached_property
|
||||
def payment_provider(self):
|
||||
|
||||
@@ -142,22 +142,26 @@ class Voucher(LoggedModel):
|
||||
item = models.ForeignKey(
|
||||
Item, related_name='vouchers',
|
||||
verbose_name=_("Product"),
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
null=True, blank=True,
|
||||
on_delete=models.PROTECT, # We use a fake version of SET_NULL in Item.delete()
|
||||
help_text=_(
|
||||
"This product is added to the user's cart if the voucher is redeemed."
|
||||
)
|
||||
)
|
||||
variation = models.ForeignKey(
|
||||
ItemVariation, related_name='vouchers',
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
null=True, blank=True,
|
||||
on_delete=models.PROTECT, # We use a fake version of SET_NULL in ItemVariation.delete() to avoid the semantic change
|
||||
# that would happen if we just set variation to None
|
||||
verbose_name=_("Product variation"),
|
||||
help_text=_(
|
||||
"This variation of the product select above is being used."
|
||||
)
|
||||
)
|
||||
quota = models.ForeignKey(
|
||||
Quota, related_name='quota',
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
Quota, related_name='vouchers',
|
||||
null=True, blank=True,
|
||||
on_delete=models.PROTECT, # We use a fake version of SET_NULL in Quota.delete()
|
||||
verbose_name=_("Quota"),
|
||||
help_text=_(
|
||||
"If enabled, the voucher is valid for any product affected by this quota."
|
||||
@@ -408,4 +412,7 @@ class Voucher(LoggedModel):
|
||||
kwargs['subevent'] = self.subevent
|
||||
if self.quota_id:
|
||||
return SeatCategoryMapping.objects.filter(product__quotas__pk=self.quota_id, **kwargs).exists()
|
||||
return self.item.seat_category_mappings.filter(**kwargs).exists()
|
||||
elif self.item_id:
|
||||
return self.item.seat_category_mappings.filter(**kwargs).exists()
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -249,9 +249,7 @@ class BasePaymentProvider:
|
||||
('_fee_percent',
|
||||
forms.DecimalField(
|
||||
label=_('Additional fee'),
|
||||
help_text=_('Percentage of the order total. Note that this percentage will currently only '
|
||||
'be calculated on the summed price of sold tickets, not on other fees like e.g. shipping '
|
||||
'fees, if there are any.'),
|
||||
help_text=_('Percentage of the order total.'),
|
||||
localize=True,
|
||||
required=False,
|
||||
)),
|
||||
@@ -298,11 +296,12 @@ class BasePaymentProvider:
|
||||
"""
|
||||
return ""
|
||||
|
||||
def render_invoice_text(self, order: Order) -> str:
|
||||
def render_invoice_text(self, order: Order, payment: OrderPayment) -> str:
|
||||
"""
|
||||
This is called when an invoice for an order with this payment provider is generated.
|
||||
The default implementation returns the content of the _invoice_text configuration
|
||||
variable (an I18nString), or an empty string if unconfigured.
|
||||
variable (an I18nString), or an empty string if unconfigured. For paid orders, the
|
||||
default implementation always renders a string stating that the invoice is already paid.
|
||||
"""
|
||||
if order.status == Order.STATUS_PAID:
|
||||
return pgettext_lazy('invoice', 'The payment for this invoice has already been received.')
|
||||
@@ -547,13 +546,14 @@ class BasePaymentProvider:
|
||||
"""
|
||||
return None
|
||||
|
||||
def order_pending_mail_render(self, order: Order) -> str:
|
||||
def order_pending_mail_render(self, order: Order, payment: OrderPayment) -> str:
|
||||
"""
|
||||
After the user has submitted their order, they will receive a confirmation
|
||||
email. You can return a string from this method if you want to add additional
|
||||
information to this email.
|
||||
|
||||
:param order: The order object
|
||||
:param payment: The payment object
|
||||
"""
|
||||
return ""
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
("event_date_range", {
|
||||
"label": _("Event date range"),
|
||||
"editor_sample": _("May 31st – June 4th, 2017"),
|
||||
"evaluate": lambda op, order, ev: ev.get_date_range_display()
|
||||
"evaluate": lambda op, order, ev: ev.get_date_range_display(force_show_end=True)
|
||||
}),
|
||||
("event_begin", {
|
||||
"label": _("Event begin date and time"),
|
||||
|
||||
@@ -26,6 +26,7 @@ from pretix.base.services.locking import LockTimeoutException, NoLockManager
|
||||
from pretix.base.services.pricing import get_price
|
||||
from pretix.base.services.tasks import ProfiledEventTask
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.signals import validate_cart_addons
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.celery_app import app
|
||||
from pretix.presale.signals import (
|
||||
@@ -225,7 +226,10 @@ class CartManager:
|
||||
|
||||
def _check_item_constraints(self, op):
|
||||
if isinstance(op, self.AddOperation) or isinstance(op, self.ExtendOperation):
|
||||
if (op.item.require_voucher or op.item.hide_without_voucher) and (op.voucher is None or not op.voucher.show_hidden_items):
|
||||
if op.item.require_voucher and op.voucher is None:
|
||||
raise CartError(error_messages['voucher_required'])
|
||||
|
||||
if op.item.hide_without_voucher and (op.voucher is None or not op.voucher.show_hidden_items):
|
||||
raise CartError(error_messages['voucher_required'])
|
||||
|
||||
if not op.item.is_available() or (op.variation and not op.variation.active):
|
||||
@@ -640,6 +644,15 @@ class CartManager:
|
||||
'cat': str(iao.addon_category.name),
|
||||
}
|
||||
)
|
||||
validate_cart_addons.send(
|
||||
sender=self.event,
|
||||
addons={
|
||||
(self._items_cache[s[0]], self._variations_cache[s[1]] if s[1] else None)
|
||||
for s in selected
|
||||
},
|
||||
base_position=cp,
|
||||
iao=iao
|
||||
)
|
||||
|
||||
# Detect removed add-ons and create RemoveOperations
|
||||
for cp, al in current_addons.items():
|
||||
@@ -935,6 +948,12 @@ def update_tax_rates(event: Event, cart_id: str, invoice_address: InvoiceAddress
|
||||
def get_fees(event, request, total, invoice_address, provider):
|
||||
fees = []
|
||||
|
||||
for recv, resp in fee_calculation_for_cart.send(sender=event, request=request, invoice_address=invoice_address,
|
||||
total=total):
|
||||
if resp:
|
||||
fees += resp
|
||||
|
||||
total = total + sum(f.value for f in fees)
|
||||
if provider and total != 0:
|
||||
provider = event.get_payment_providers().get(provider)
|
||||
if provider:
|
||||
@@ -960,10 +979,6 @@ def get_fees(event, request, total, invoice_address, provider):
|
||||
tax_rule=payment_fee_tax_rule
|
||||
))
|
||||
|
||||
for recv, resp in fee_calculation_for_cart.send(sender=event, request=request, invoice_address=invoice_address,
|
||||
total=total):
|
||||
fees += resp
|
||||
|
||||
return fees
|
||||
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ def _save_answers(op, answers, given_answers):
|
||||
@transaction.atomic
|
||||
def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict, force=False,
|
||||
ignore_unpaid=False, nonce=None, datetime=None, questions_supported=True,
|
||||
user=None, auth=None):
|
||||
user=None, auth=None, canceled_supported=False):
|
||||
"""
|
||||
Create a checkin for this particular order position and check-in list. Fails with CheckInError if the check in is
|
||||
not valid at this time.
|
||||
@@ -90,10 +90,10 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
|
||||
'answers'
|
||||
).get(pk=op.pk)
|
||||
|
||||
if op.canceled:
|
||||
if op.canceled or op.order.status not in (Order.STATUS_PAID, Order.STATUS_PENDING):
|
||||
raise CheckInError(
|
||||
_('This order position has been canceled.'),
|
||||
'unpaid'
|
||||
'canceled' if canceled_supported else 'unpaid'
|
||||
)
|
||||
|
||||
answers = {a.question: a for a in op.answers.all()}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import inspect
|
||||
import json
|
||||
import logging
|
||||
import urllib.error
|
||||
@@ -53,7 +54,10 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
||||
additional = invoice.event.settings.get('invoice_additional_text', as_type=LazyI18nString)
|
||||
footer = invoice.event.settings.get('invoice_footer_text', as_type=LazyI18nString)
|
||||
if open_payment and open_payment.payment_provider:
|
||||
payment = open_payment.payment_provider.render_invoice_text(invoice.order)
|
||||
if 'payment' in inspect.signature(open_payment.payment_provider.render_invoice_text).parameters:
|
||||
payment = open_payment.payment_provider.render_invoice_text(invoice.order, open_payment)
|
||||
else:
|
||||
payment = open_payment.payment_provider.render_invoice_text(invoice.order)
|
||||
elif invoice.order.status == Order.STATUS_PAID:
|
||||
payment = pgettext('invoice', 'The payment for this invoice has already been received.')
|
||||
else:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import inspect
|
||||
import logging
|
||||
import smtplib
|
||||
import warnings
|
||||
@@ -177,9 +178,9 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
||||
body_plain += "\r\n"
|
||||
|
||||
try:
|
||||
try:
|
||||
if 'position' in inspect.signature(renderer.render).parameters:
|
||||
body_html = renderer.render(content_plain, signature, str(subject), order, position)
|
||||
except TypeError:
|
||||
else:
|
||||
# Backwards compatibility
|
||||
warnings.warn('E-mail renderer called without position argument because position argument is not '
|
||||
'supported.',
|
||||
|
||||
@@ -32,7 +32,7 @@ def notify(logentry_id: int):
|
||||
# All users that have the permission to get the notification
|
||||
users = logentry.event.get_users_with_permission(
|
||||
notification_type.required_permission
|
||||
).filter(notifications_send=True)
|
||||
).filter(notifications_send=True, is_active=True)
|
||||
if logentry.user:
|
||||
users = users.exclude(pk=logentry.user.pk)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import inspect
|
||||
import json
|
||||
import logging
|
||||
from collections import Counter, namedtuple
|
||||
@@ -48,7 +49,7 @@ from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.signals import (
|
||||
allow_ticket_download, order_approved, order_canceled, order_changed,
|
||||
order_denied, order_expired, order_fee_calculation, order_placed,
|
||||
periodic_task, validate_order,
|
||||
order_split, periodic_task, validate_order,
|
||||
)
|
||||
from pretix.celery_app import app
|
||||
from pretix.helpers.models import modelcopy
|
||||
@@ -505,7 +506,7 @@ def _check_positions(event: Event, now_dt: datetime, positions: List[CartPositio
|
||||
err = err or error_messages['voucher_required']
|
||||
break
|
||||
|
||||
if cp.item.hide_without_voucher and (cp.voucher is None or not cp.voucher.show_hidden_items or not cp.voucher.applies_to(cp.item.pk, cp.variation.pk)):
|
||||
if cp.item.hide_without_voucher and (cp.voucher is None or not cp.voucher.show_hidden_items or not cp.voucher.applies_to(cp.item, cp.variation)):
|
||||
delete(cp)
|
||||
cp.delete()
|
||||
err = error_messages['voucher_required']
|
||||
@@ -591,6 +592,13 @@ def _get_fees(positions: List[CartPosition], payment_provider: BasePaymentProvid
|
||||
meta_info: dict, event: Event):
|
||||
fees = []
|
||||
total = sum([c.price for c in positions])
|
||||
|
||||
for recv, resp in order_fee_calculation.send(sender=event, invoice_address=address, total=total,
|
||||
meta_info=meta_info, positions=positions):
|
||||
if resp:
|
||||
fees += resp
|
||||
|
||||
total += sum(f.value for f in fees)
|
||||
if payment_provider:
|
||||
payment_fee = payment_provider.calculate_fee(total)
|
||||
else:
|
||||
@@ -601,9 +609,6 @@ def _get_fees(positions: List[CartPosition], payment_provider: BasePaymentProvid
|
||||
internal_type=payment_provider.identifier)
|
||||
fees.append(pf)
|
||||
|
||||
for recv, resp in order_fee_calculation.send(sender=event, invoice_address=address, total=total,
|
||||
meta_info=meta_info, positions=positions):
|
||||
fees += resp
|
||||
return fees, pf
|
||||
|
||||
|
||||
@@ -666,7 +671,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
||||
|
||||
|
||||
def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider, email_template, log_entry: str,
|
||||
invoice):
|
||||
invoice, payment: OrderPayment):
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
invoice_company = order.invoice_address.company
|
||||
@@ -675,7 +680,10 @@ def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider,
|
||||
invoice_company = ""
|
||||
|
||||
if pprov:
|
||||
payment_info = str(pprov.order_pending_mail_render(order))
|
||||
if 'payment' in inspect.signature(pprov.order_pending_mail_render).parameters:
|
||||
payment_info = str(pprov.order_pending_mail_render(order, payment))
|
||||
else:
|
||||
payment_info = str(pprov.order_pending_mail_render(order))
|
||||
else:
|
||||
payment_info = None
|
||||
|
||||
@@ -821,7 +829,7 @@ def _perform_order(event: Event, payment_provider: str, position_ids: List[str],
|
||||
email_attendees = event.settings.mail_send_order_placed_attendee
|
||||
email_attendees_template = event.settings.mail_text_order_placed_attendee
|
||||
|
||||
_order_placed_email(event, order, pprov, email_template, log_entry, invoice)
|
||||
_order_placed_email(event, order, pprov, email_template, log_entry, invoice, payment)
|
||||
if email_attendees:
|
||||
for p in order.positions.all():
|
||||
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
|
||||
@@ -975,6 +983,35 @@ def send_download_reminders(sender, **kwargs):
|
||||
logger.exception('Reminder email could not be sent to attendee')
|
||||
|
||||
|
||||
def notify_user_changed_order(order, user=None, auth=None):
|
||||
with language(order.locale):
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
invoice_company = order.invoice_address.company
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
email_template = order.event.settings.mail_text_order_changed
|
||||
email_context = {
|
||||
'event': order.event.name,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order.open', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret,
|
||||
'hash': order.email_confirm_hash()
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
email_subject = _('Your order has been changed: %(code)s') % {'code': order.code}
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_changed', user, auth=auth
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order changed email could not be sent')
|
||||
|
||||
|
||||
class OrderChangeManager:
|
||||
error_messages = {
|
||||
'product_without_variation': _('You need to select a variation of the product.'),
|
||||
@@ -1377,6 +1414,14 @@ class OrderChangeManager:
|
||||
pass
|
||||
|
||||
split_order.total = sum([p.price for p in split_positions if not p.canceled])
|
||||
|
||||
for fee in self.order.fees.exclude(fee_type=OrderFee.FEE_TYPE_PAYMENT):
|
||||
new_fee = modelcopy(fee)
|
||||
new_fee.pk = None
|
||||
new_fee.order = split_order
|
||||
split_order.total += new_fee.value
|
||||
new_fee.save()
|
||||
|
||||
if split_order.total != Decimal('0.00') and self.order.status != Order.STATUS_PAID:
|
||||
pp = self._get_payment_provider()
|
||||
if pp:
|
||||
@@ -1392,13 +1437,6 @@ class OrderChangeManager:
|
||||
fee.delete()
|
||||
split_order.total += fee.value
|
||||
|
||||
for fee in self.order.fees.exclude(fee_type=OrderFee.FEE_TYPE_PAYMENT):
|
||||
new_fee = modelcopy(fee)
|
||||
new_fee.pk = None
|
||||
new_fee.order = split_order
|
||||
split_order.total += new_fee.value
|
||||
new_fee.save()
|
||||
|
||||
split_order.save()
|
||||
|
||||
if split_order.status == Order.STATUS_PAID:
|
||||
@@ -1419,6 +1457,8 @@ class OrderChangeManager:
|
||||
|
||||
if split_order.total != Decimal('0.00') and self.order.invoices.filter(is_cancellation=False).last():
|
||||
generate_invoice(split_order)
|
||||
|
||||
order_split.send(sender=self.order.event, original=self.order, split_order=split_order)
|
||||
return split_order
|
||||
|
||||
@cached_property
|
||||
@@ -1504,34 +1544,6 @@ class OrderChangeManager:
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
return None
|
||||
|
||||
def _notify_user(self, order):
|
||||
with language(order.locale):
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
invoice_company = order.invoice_address.company
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
email_template = order.event.settings.mail_text_order_changed
|
||||
email_context = {
|
||||
'event': order.event.name,
|
||||
'url': build_absolute_uri(self.order.event, 'presale:event.order.open', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret,
|
||||
'hash': order.email_confirm_hash()
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
email_subject = _('Your order has been changed: %(code)s') % {'code': order.code}
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_changed', self.user, auth=self.auth
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order changed email could not be sent')
|
||||
|
||||
def commit(self, check_quotas=True):
|
||||
if self._committed:
|
||||
# an order change can only be committed once
|
||||
@@ -1562,9 +1574,9 @@ class OrderChangeManager:
|
||||
self._check_paid_to_free()
|
||||
|
||||
if self.notify:
|
||||
self._notify_user(self.order)
|
||||
notify_user_changed_order(self.order, self.user, self.auth)
|
||||
if self.split_order:
|
||||
self._notify_user(self.split_order)
|
||||
notify_user_changed_order(self.split_order, self.user, self.auth)
|
||||
|
||||
order_changed.send(self.order.event, order=self.order)
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import Any, Dict, Iterable, List, Tuple
|
||||
|
||||
from django.db.models import Case, Count, F, Sum, Value, When
|
||||
from django.db.models import (
|
||||
Case, Count, DateTimeField, F, Max, OuterRef, Subquery, Sum, Value, When,
|
||||
)
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from pretix.base.models import Event, Item, ItemCategory, Order, OrderPosition
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.models.orders import OrderFee, OrderPayment
|
||||
from pretix.base.signals import order_fee_type_name
|
||||
|
||||
|
||||
@@ -71,8 +75,9 @@ def dictsum(*dicts) -> dict:
|
||||
return res
|
||||
|
||||
|
||||
def order_overview(event: Event, subevent: SubEvent=None) -> Tuple[List[Tuple[ItemCategory, List[Item]]],
|
||||
Dict[str, Tuple[Decimal, Decimal]]]:
|
||||
def order_overview(
|
||||
event: Event, subevent: SubEvent=None, date_filter='', date_from=None, date_until=None
|
||||
) -> Tuple[List[Tuple[ItemCategory, List[Item]]], Dict[str, Tuple[Decimal, Decimal]]]:
|
||||
items = event.items.all().select_related(
|
||||
'category', # for re-grouping
|
||||
).prefetch_related(
|
||||
@@ -82,6 +87,38 @@ def order_overview(event: Event, subevent: SubEvent=None) -> Tuple[List[Tuple[It
|
||||
qs = OrderPosition.all
|
||||
if subevent:
|
||||
qs = qs.filter(subevent=subevent)
|
||||
|
||||
if date_from and isinstance(date_from, date):
|
||||
date_from = make_aware(datetime.combine(
|
||||
date_from,
|
||||
time(hour=0, minute=0, second=0, microsecond=0)
|
||||
), event.timezone)
|
||||
|
||||
if date_until and isinstance(date_until, date):
|
||||
date_until = make_aware(datetime.combine(
|
||||
date_until + timedelta(days=1),
|
||||
time(hour=0, minute=0, second=0, microsecond=0)
|
||||
), event.timezone)
|
||||
|
||||
if date_filter == 'order_date':
|
||||
if date_from:
|
||||
qs = qs.filter(order__datetime__gte=date_from)
|
||||
if date_until:
|
||||
qs = qs.filter(order__datetime__lt=date_until)
|
||||
elif date_filter == 'last_payment_date':
|
||||
p_date = OrderPayment.objects.filter(
|
||||
order=OuterRef('order'),
|
||||
state__in=[OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED],
|
||||
payment_date__isnull=False
|
||||
).values('order').annotate(
|
||||
m=Max('payment_date')
|
||||
).values('m').order_by()
|
||||
qs = qs.annotate(payment_date=Subquery(p_date, output_field=DateTimeField()))
|
||||
if date_from:
|
||||
qs = qs.filter(payment_date__gte=date_from)
|
||||
if date_until:
|
||||
qs = qs.filter(payment_date__lt=date_until)
|
||||
|
||||
counters = qs.filter(
|
||||
order__event=event
|
||||
).annotate(
|
||||
@@ -153,14 +190,26 @@ def order_overview(event: Event, subevent: SubEvent=None) -> Tuple[List[Tuple[It
|
||||
payment_items = []
|
||||
|
||||
if not subevent:
|
||||
counters = OrderFee.all.filter(
|
||||
qs = OrderFee.all.filter(
|
||||
order__event=event
|
||||
).annotate(
|
||||
status=Case(
|
||||
When(canceled=True, then=Value('c')),
|
||||
default=F('order__status')
|
||||
)
|
||||
).values(
|
||||
)
|
||||
if date_filter == 'order_date':
|
||||
if date_from:
|
||||
qs = qs.filter(order__datetime__gte=date_from)
|
||||
if date_until:
|
||||
qs = qs.filter(order__datetime__lt=date_until)
|
||||
elif date_filter == 'last_payment_date':
|
||||
qs = qs.annotate(payment_date=Subquery(p_date, output_field=DateTimeField()))
|
||||
if date_from:
|
||||
qs = qs.filter(payment_date__gte=date_from)
|
||||
if date_until:
|
||||
qs = qs.filter(payment_date__lt=date_until)
|
||||
counters = qs.values(
|
||||
'fee_type', 'internal_type', 'status'
|
||||
).annotate(cnt=Count('id'), value=Sum('value'), tax_value=Sum('tax_value')).order_by()
|
||||
|
||||
|
||||
@@ -701,6 +701,23 @@ Your {event} team"""))
|
||||
'type': str
|
||||
}
|
||||
}
|
||||
PERSON_NAME_TITLE_GROUPS = OrderedDict([
|
||||
('english_common', (_('Most common English titles'), (
|
||||
'Mr',
|
||||
'Ms',
|
||||
'Mrs',
|
||||
'Miss',
|
||||
'Mx',
|
||||
'Dr',
|
||||
'Professor',
|
||||
'Sir'
|
||||
))),
|
||||
('german_common', (_('Most common German titles'), (
|
||||
'Dr.',
|
||||
'Prof.',
|
||||
'Prof. Dr.',
|
||||
)))
|
||||
])
|
||||
PERSON_NAME_SCHEMES = OrderedDict([
|
||||
('given_family', {
|
||||
'fields': (
|
||||
@@ -730,6 +747,22 @@ PERSON_NAME_SCHEMES = OrderedDict([
|
||||
'_scheme': 'title_given_family',
|
||||
},
|
||||
}),
|
||||
('title_given_family', {
|
||||
'fields': (
|
||||
('title', pgettext_lazy('person_name', 'Title'), 1),
|
||||
('given_name', _('Given name'), 2),
|
||||
('family_name', _('Family name'), 2),
|
||||
),
|
||||
'concatenation': lambda d: ' '.join(
|
||||
str(p) for p in [d.get('title', ''), d.get('given_name', ''), d.get('family_name', '')] if p
|
||||
),
|
||||
'sample': {
|
||||
'title': pgettext_lazy('person_name_sample', 'Dr'),
|
||||
'given_name': pgettext_lazy('person_name_sample', 'John'),
|
||||
'family_name': pgettext_lazy('person_name_sample', 'Doe'),
|
||||
'_scheme': 'title_given_family',
|
||||
},
|
||||
}),
|
||||
('given_middle_family', {
|
||||
'fields': (
|
||||
('given_name', _('First name'), 2),
|
||||
|
||||
@@ -265,6 +265,21 @@ appropriate exception message.
|
||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
validate_cart_addons = EventPluginSignal(
|
||||
providing_args=["addons", "base_position", "iao"]
|
||||
)
|
||||
"""
|
||||
This signal is sent when a user tries to select a combination of addons. In contrast to
|
||||
``validate_cart``, this is executed before the cart is actually modified. You are passed
|
||||
an argument ``addons`` containing a set of ``(item, variation or None)`` tuples as well
|
||||
as the ``ItemAddOn`` object as the argument ``iao`` and the base cart position as
|
||||
``base_position``.
|
||||
The response of receivers will be ignored, but you can raise a CartError with an
|
||||
appropriate exception message.
|
||||
|
||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
order_placed = EventPluginSignal(
|
||||
providing_args=["order"]
|
||||
)
|
||||
@@ -541,3 +556,11 @@ into account.
|
||||
system really bad.** Also, keep in mind that your response is subject to caching and out-of-date
|
||||
quotas might be used for display (not for actual order processing).
|
||||
"""
|
||||
|
||||
order_split = EventPluginSignal(
|
||||
providing_args=["original", "split_order"]
|
||||
)
|
||||
"""
|
||||
This signal is sent out when an order is split into two orders and allows you to copy related models
|
||||
to the new order. You will be passed the old order as ``original`` and the new order as ``split_order``.
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import json
|
||||
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
|
||||
@@ -11,3 +13,9 @@ register = template.Library()
|
||||
def escapejs_filter(value):
|
||||
"""Hex encodes characters for use in a application/json type script."""
|
||||
return escapejson(value)
|
||||
|
||||
|
||||
@register.filter("escapejson_dumps")
|
||||
def escapejs_dumps_filter(value):
|
||||
"""Hex encodes characters for use in a application/json type script."""
|
||||
return escapejson(json.dumps(value))
|
||||
|
||||
@@ -24,7 +24,7 @@ from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
|
||||
from pretix.base.models import Event, Organizer, TaxRule
|
||||
from pretix.base.models.event import EventMetaValue, SubEvent
|
||||
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS
|
||||
from pretix.control.forms import (
|
||||
ExtFileField, FontSelect, MultipleLanguagesWidget, SingleLanguageWidget,
|
||||
SlugWidget, SplitDateTimeField, SplitDateTimePickerWidget,
|
||||
@@ -383,6 +383,12 @@ class EventSettingsForm(SettingsForm):
|
||||
"orders might lead to unexpected behaviour when sorting or changing names."),
|
||||
required=True,
|
||||
)
|
||||
name_scheme_titles = forms.ChoiceField(
|
||||
label=_("Allowed titles"),
|
||||
help_text=_("If the naming scheme you defined above allows users to input a title, you can use this to "
|
||||
"restrict the set of selectable titles."),
|
||||
required=False,
|
||||
)
|
||||
attendee_emails_asked = forms.BooleanField(
|
||||
label=_("Ask for email addresses per ticket"),
|
||||
help_text=_("Normally, pretix asks for one email address per order and the order confirmation will be sent "
|
||||
@@ -466,6 +472,13 @@ class EventSettingsForm(SettingsForm):
|
||||
))
|
||||
for k, v in PERSON_NAME_SCHEMES.items()
|
||||
)
|
||||
self.fields['name_scheme_titles'].choices = [('', _('Free text input'))] + [
|
||||
(k, '{scheme}: {samples}'.format(
|
||||
scheme=v[0],
|
||||
samples=', '.join(v[1])
|
||||
))
|
||||
for k, v in PERSON_NAME_TITLE_GROUPS.items()
|
||||
]
|
||||
|
||||
|
||||
class CancelSettingsForm(SettingsForm):
|
||||
@@ -1194,6 +1207,10 @@ class DisplaySettingsForm(SettingsForm):
|
||||
label=_("Show variations of a product expanded by default"),
|
||||
required=False
|
||||
)
|
||||
hide_sold_out = forms.BooleanField(
|
||||
label=_("Hide all products that are sold out"),
|
||||
required=False
|
||||
)
|
||||
frontpage_subevent_ordering = forms.ChoiceField(
|
||||
label=pgettext('subevent', 'Date ordering'),
|
||||
choices=[
|
||||
|
||||
@@ -940,3 +940,51 @@ class RefundFilterForm(FilterForm):
|
||||
OrderRefund.REFUND_STATE_EXTERNAL])
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class OverviewFilterForm(FilterForm):
|
||||
subevent = forms.ModelChoiceField(
|
||||
label=pgettext_lazy('subevent', 'Date'),
|
||||
queryset=SubEvent.objects.none(),
|
||||
required=False,
|
||||
empty_label=pgettext_lazy('subevent', 'All dates')
|
||||
)
|
||||
date_axis = forms.ChoiceField(
|
||||
label=_('Date filter'),
|
||||
choices=(
|
||||
('', _('Filter by…')),
|
||||
('order_date', _('Order date')),
|
||||
('last_payment_date', _('Date of last successful payment')),
|
||||
),
|
||||
required=False,
|
||||
)
|
||||
date_from = forms.DateField(
|
||||
label=_('Date from'),
|
||||
required=False,
|
||||
widget=DatePickerWidget,
|
||||
)
|
||||
date_until = forms.DateField(
|
||||
label=_('Date until'),
|
||||
required=False,
|
||||
widget=DatePickerWidget,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if self.event.has_subevents:
|
||||
self.fields['subevent'].queryset = self.event.subevents.all()
|
||||
self.fields['subevent'].widget = Select2(
|
||||
attrs={
|
||||
'data-model-select2': 'event',
|
||||
'data-select2-url': reverse('control:event.subevents.select2', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
}),
|
||||
'data-placeholder': pgettext_lazy('subevent', 'All dates')
|
||||
}
|
||||
)
|
||||
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
|
||||
elif 'subevent':
|
||||
del self.fields['subevent']
|
||||
|
||||
@@ -55,8 +55,13 @@ class QuestionForm(I18nModelForm):
|
||||
pk=self.instance.pk
|
||||
)
|
||||
self.fields['identifier'].required = False
|
||||
self.fields['dependency_values'].required = False
|
||||
self.fields['help_text'].widget.attrs['rows'] = 3
|
||||
|
||||
def clean_dependency_values(self):
|
||||
val = self.data.getlist('dependency_values')
|
||||
return val
|
||||
|
||||
def clean_dependency_question(self):
|
||||
dep = val = self.cleaned_data.get('dependency_question')
|
||||
if dep:
|
||||
@@ -70,8 +75,8 @@ class QuestionForm(I18nModelForm):
|
||||
|
||||
def clean(self):
|
||||
d = super().clean()
|
||||
if d.get('dependency_question') and not d.get('dependency_value'):
|
||||
raise ValidationError({'dependency_value': [_('This field is required')]})
|
||||
if d.get('dependency_question') and not d.get('dependency_values'):
|
||||
raise ValidationError({'dependency_values': [_('This field is required')]})
|
||||
if d.get('dependency_question') and d.get('ask_during_checkin'):
|
||||
raise ValidationError(_('Dependencies between questions are not supported during check-in.'))
|
||||
return d
|
||||
@@ -89,13 +94,13 @@ class QuestionForm(I18nModelForm):
|
||||
'identifier',
|
||||
'items',
|
||||
'dependency_question',
|
||||
'dependency_value'
|
||||
'dependency_values'
|
||||
]
|
||||
widgets = {
|
||||
'items': forms.CheckboxSelectMultiple(
|
||||
attrs={'class': 'scrolling-multiple-choice'}
|
||||
),
|
||||
'dependency_value': forms.Select,
|
||||
'dependency_values': forms.SelectMultiple,
|
||||
}
|
||||
field_classes = {
|
||||
'items': SafeModelMultipleChoiceField,
|
||||
@@ -164,7 +169,8 @@ class QuotaForm(I18nModelForm):
|
||||
fields = [
|
||||
'name',
|
||||
'size',
|
||||
'subevent'
|
||||
'subevent',
|
||||
'close_when_sold_out'
|
||||
]
|
||||
field_classes = {
|
||||
'subevent': SafeModelChoiceField,
|
||||
@@ -356,6 +362,16 @@ class ItemCreateForm(I18nModelForm):
|
||||
]
|
||||
|
||||
|
||||
class ShowQuotaNullBooleanSelect(forms.NullBooleanSelect):
|
||||
def __init__(self, attrs=None):
|
||||
choices = (
|
||||
('1', _('(Event default)')),
|
||||
('2', _('Yes')),
|
||||
('3', _('No')),
|
||||
)
|
||||
super(forms.NullBooleanSelect, self).__init__(attrs, choices)
|
||||
|
||||
|
||||
class TicketNullBooleanSelect(forms.NullBooleanSelect):
|
||||
def __init__(self, attrs=None):
|
||||
choices = (
|
||||
@@ -415,6 +431,7 @@ class ItemUpdateForm(I18nModelForm):
|
||||
'generate_tickets',
|
||||
'original_price',
|
||||
'require_bundling',
|
||||
'show_quota_left'
|
||||
]
|
||||
field_classes = {
|
||||
'available_from': SplitDateTimeField,
|
||||
@@ -423,7 +440,8 @@ class ItemUpdateForm(I18nModelForm):
|
||||
widgets = {
|
||||
'available_from': SplitDateTimePickerWidget(),
|
||||
'available_until': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_available_from_0'}),
|
||||
'generate_tickets': TicketNullBooleanSelect()
|
||||
'generate_tickets': TicketNullBooleanSelect(),
|
||||
'show_quota_left': ShowQuotaNullBooleanSelect()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -173,6 +173,13 @@ class DeviceForm(forms.ModelForm):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['limit_events'].queryset = organizer.events.all()
|
||||
|
||||
def clean(self):
|
||||
d = super().clean()
|
||||
if not d['all_events'] and not d['limit_events']:
|
||||
raise ValidationError(_('Your device will not have access to anything, please select some events.'))
|
||||
|
||||
return d
|
||||
|
||||
class Meta:
|
||||
model = Device
|
||||
fields = ['name', 'all_events', 'limit_events']
|
||||
|
||||
@@ -148,14 +148,16 @@ class VoucherForm(I18nModelForm):
|
||||
data, self.instance.event,
|
||||
self.instance.quota, self.instance.item, self.instance.variation
|
||||
)
|
||||
if self.instance.quota:
|
||||
if all(i.hide_without_voucher for i in self.instance.quota.items.all()):
|
||||
raise ValidationError({
|
||||
'itemvar': [
|
||||
_('The quota you selected only contains hidden products. Hidden products can currently only be '
|
||||
'shown by using vouchers that directly apply to the product, not via a quota.')
|
||||
]
|
||||
})
|
||||
if not self.instance.show_hidden_items and (
|
||||
(self.instance.quota and all(i.hide_without_voucher for i in self.instance.quota.items.all()))
|
||||
or (self.instance.item and self.instance.item.hide_without_voucher)
|
||||
):
|
||||
raise ValidationError({
|
||||
'show_hidden_items': [
|
||||
_('The voucher only matches hidden products but you have not selected that it should show '
|
||||
'them.')
|
||||
]
|
||||
})
|
||||
Voucher.clean_subevent(
|
||||
data, self.instance.event
|
||||
)
|
||||
|
||||
@@ -263,6 +263,8 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.quota.added': _('The quota has been added.'),
|
||||
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
||||
'pretix.event.quota.changed': _('The quota has been changed.'),
|
||||
'pretix.event.quota.closed': _('The quota has closed.'),
|
||||
'pretix.event.quota.opened': _('The quota has been re-opened.'),
|
||||
'pretix.event.category.added': _('The category has been added.'),
|
||||
'pretix.event.category.deleted': _('The category has been deleted.'),
|
||||
'pretix.event.category.changed': _('The category has been changed.'),
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
{% bootstrap_field form.presale_has_ended_text layout="control" %}
|
||||
{% bootstrap_field form.voucher_explanation_text layout="control" %}
|
||||
{% bootstrap_field form.show_variations_expanded layout="control" %}
|
||||
{% bootstrap_field form.hide_sold_out layout="control" %}
|
||||
{% bootstrap_field form.meta_noindex layout="control" %}
|
||||
{% if form.frontpage_subevent_ordering %}
|
||||
{% bootstrap_field form.frontpage_subevent_ordering layout="control" %}
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
{% bootstrap_field sform.attendee_names_asked layout="control" %}
|
||||
{% bootstrap_field sform.attendee_names_required layout="control" %}
|
||||
{% bootstrap_field sform.name_scheme layout="control" %}
|
||||
{% bootstrap_field sform.name_scheme_titles layout="control" %}
|
||||
{% bootstrap_field sform.order_email_asked_twice layout="control" %}
|
||||
{% bootstrap_field sform.attendee_emails_asked layout="control" %}
|
||||
{% bootstrap_field sform.attendee_emails_required layout="control" %}
|
||||
|
||||
@@ -87,6 +87,11 @@
|
||||
<td class="event-name-col">
|
||||
<strong><a href="{% url "control:event.index" organizer=e.organizer.slug event=e.slug %}">{{ e.name }}</a></strong>
|
||||
<br><small>{{ e.slug }}</small>
|
||||
{% for k, v in e.meta_data.items %}
|
||||
{% if v %}
|
||||
<span class="text-muted">· {{ k }}: {{ v }}</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% if not hide_orga %}<td>{{ e.organizer }}</td>{% endif %}
|
||||
<td class="event-date-col">
|
||||
|
||||
@@ -17,6 +17,19 @@
|
||||
{% csrf_token %}
|
||||
{% if possible %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the product <strong>{{ item }}</strong>?{% endblocktrans %}</p>
|
||||
{% if vouchers %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed count count=vouchers %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% plural %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% endblocktrans %}
|
||||
<a href="{% url "control:event.vouchers" organizer=request.organizer.slug event=request.event.slug %}?itemvar={{ item.pk }}"
|
||||
class="btn btn-default">
|
||||
{% trans "Show affected vouchers" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>{% blocktrans %}You cannot delete the product <strong>{{ item }}</strong> because it already has been ordered, but you can deactivate it.{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
{% bootstrap_field form.original_price addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field form.require_approval layout="control" %}
|
||||
{% bootstrap_field form.generate_tickets layout="control" %}
|
||||
{% bootstrap_field form.show_quota_left layout="control" %}
|
||||
{% for f in plugin_forms %}
|
||||
{% bootstrap_form f layout="control" %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{% load i18n %}
|
||||
{% if availability.0 == 10 %}
|
||||
{% if closed %}
|
||||
<span class="label label-danger">{% trans "Closed" %}</span>
|
||||
{% elif availability.0 == 10 %}
|
||||
<span class="label label-warning">{% trans "Sold out (pending orders)" %}</span>
|
||||
{% elif availability.0 == 100 %}
|
||||
{% if availability.1 != None %}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load formset_tags %}
|
||||
{% load escapejson %}
|
||||
{% block title %}
|
||||
{% if question %}
|
||||
{% blocktrans with name=question.question %}Question: {{ name }}{% endblocktrans %}
|
||||
@@ -120,8 +121,8 @@
|
||||
{% bootstrap_field form.dependency_question layout="inline" form_group_class="inner" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<script type="text/plain" id="dependency_value_val">{{ form.instance.dependency_value }}</script>
|
||||
{% bootstrap_field form.dependency_value layout="inline" form_group_class="inner" %}
|
||||
<script type="text/plain" id="dependency_value_val">{{ form.instance.dependency_values|escapejson_dumps }}</script>
|
||||
{% bootstrap_field form.dependency_values layout="inline" form_group_class="inner" %}
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@@ -20,6 +20,27 @@
|
||||
<span class="fa fa-calendar"></span> {{ quota.subevent.name }} – {{ quota.subevent.get_date_range_display }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% if quota.closed %}
|
||||
{% if closed_and_sold_out %}
|
||||
<div class="alert alert-info">
|
||||
<button type="submit" class="btn btn-default pull-right" name="disable" value="true">
|
||||
{% trans "Open quota and disable closing" %}
|
||||
</button>
|
||||
{% trans "This quota is sold out and closed. Even if tickets become available e.g. through cancellations, they will not become available again unless you manually re-open the quota on this page." %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="submit" class="btn btn-primary pull-right" name="reopen" value="true">{% trans "Open quota" %}</button>
|
||||
{% trans "This quota is closed since it has been sold out before. Tickets are theoretically available, but will not be sold unless you manually re-open the quota." %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="row" id="quota-stats">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<legend>{% trans "Usage overview" %}</legend>
|
||||
@@ -30,7 +51,6 @@
|
||||
</div>
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<legend>{% trans "Availability calculation" %}</legend>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-9">{% trans "Total quota" %}</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
|
||||
@@ -3,16 +3,35 @@
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Delete quota" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Delete quota" %}</h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the quota <strong>{{ quota }}</strong>?{% endblocktrans %}</p>
|
||||
{% if dependent|length > 0 %}
|
||||
<p>{% blocktrans %}The following products might be no longer available for sale:{% endblocktrans %}</p>
|
||||
{% for item in dependent %}
|
||||
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a></li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<h1>{% trans "Delete quota" %}</h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the quota <strong>{{ quota }}</strong>?{% endblocktrans %}</p>
|
||||
{% if dependent|length > 0 %}
|
||||
<div class="alert alert-info">
|
||||
<p>{% blocktrans %}The following products might be no longer available for sale:{% endblocktrans %}</p>
|
||||
<ul>
|
||||
{% for item in dependent %}
|
||||
<li>
|
||||
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if vouchers %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed count count=vouchers %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% plural %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% endblocktrans %}
|
||||
<a href="{% url "control:event.vouchers" organizer=request.organizer.slug event=request.event.slug %}?itemvar=q-{{ quota.pk }}"
|
||||
class="btn btn-default">
|
||||
{% trans "Show affected vouchers" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default btn-cancel">
|
||||
{% trans "Cancel" %}
|
||||
@@ -20,6 +39,6 @@
|
||||
<button type="submit" class="btn btn-danger btn-save">
|
||||
{% trans "Delete" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
{% if form.subevent %}
|
||||
{% bootstrap_field form.subevent layout="control" %}
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Items" %}</legend>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
@@ -35,6 +37,10 @@
|
||||
</p>
|
||||
{% bootstrap_field form.itemvars layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Advanced options" %}</legend>
|
||||
{% bootstrap_field form.close_when_sold_out layout="control" %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<td>{{ q.subevent.name }} – {{ q.subevent.get_date_range_display }}</td>
|
||||
{% endif %}
|
||||
<td>{% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %}</td>
|
||||
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.availability %}</td>
|
||||
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.availability closed=q.closed %}</td>
|
||||
<td class="text-right">
|
||||
<a href="{% url "control:event.items.quotas.edit" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "control:event.items.quotas.delete" organizer=request.event.organizer.slug event=request.event.slug quota=q.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
|
||||
|
||||
@@ -59,6 +59,24 @@
|
||||
</details>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Other operations" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-horizontal">
|
||||
{% bootstrap_form_errors other_form %}
|
||||
{% if other_form.custom_error %}
|
||||
<div class="alert alert-danger">
|
||||
{{ other_form.custom_error }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% bootstrap_field other_form.notify layout="control" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<a class="btn btn-default btn-lg"
|
||||
href="{% url "control:event.order" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
|
||||
|
||||
@@ -332,6 +332,13 @@
|
||||
title="{% trans "This file has been uploaded by a user and could contain viruses or other malicious content." %}">
|
||||
{% trans "UNSAFE" %}
|
||||
</span>
|
||||
{% if q.answer.is_image %}
|
||||
<br>
|
||||
<a href="{{ q.answer.backend_file_url }}?token={% answer_token request q.answer %}" data-lightbox="order"
|
||||
class="answer-thumb">
|
||||
<img src="{{ q.answer.backend_file_url }}?token={% answer_token request q.answer %}">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ q.answer|linebreaksbr }}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load order_overview %}
|
||||
{% block title %}{% trans "Order overview" %}{% endblock %}
|
||||
{% block content %}
|
||||
@@ -12,11 +13,36 @@
|
||||
</div>
|
||||
</div>
|
||||
<h1>{% trans "Order overview" %}</h1>
|
||||
{% if request.event.has_subevents %}
|
||||
<form class="form-inline helper-display-inline" action="" method="get">
|
||||
{% include "pretixcontrol/event/fragment_subevent_choice_simple.html" %}
|
||||
<div class="row filter-form">
|
||||
<form class="" action="" method="get">
|
||||
{% if request.event.has_subevents %}
|
||||
<div class="col-lg-2 col-sm-3 col-xs-6">
|
||||
{% bootstrap_field filter_form.subevent layout='inline' %}
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-3 col-xs-6">
|
||||
{% bootstrap_field filter_form.date_axis layout='inline' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-lg-4 col-sm-6 col-xs-6">
|
||||
{% bootstrap_field filter_form.date_axis layout='inline' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-lg-2 col-sm-6 col-xs-6">
|
||||
{% bootstrap_field filter_form.date_from layout='inline' %}
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-6 col-xs-6">
|
||||
{% bootstrap_field filter_form.date_until layout='inline' %}
|
||||
</div>
|
||||
<div class="col-lg-1 col-lg-offset-3 col-sm-6 col-xs-6">
|
||||
<button class="btn btn-primary btn-block" type="submit">
|
||||
<span class="fa fa-filter"></span>
|
||||
<span class="hidden-md">
|
||||
{% trans "Filter" %}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if subevent_warning %}
|
||||
<div class="alert alert-info">
|
||||
{% blocktrans trimmed context "subevent" %}
|
||||
|
||||
@@ -7,7 +7,16 @@
|
||||
|
||||
<div>
|
||||
<ol>
|
||||
<li>{% trans "Open the app that you want to connect and optionally reset it to the original state." %}</li>
|
||||
<li>
|
||||
{% trans "Download an app that is compatible with pretix. For example, our check-in app <strong>pretixSCAN</strong> is available on all major platforms." %}<br>
|
||||
<a href="https://pretix.eu/about/{% if "de" in request.LANGUAGE_CODE %}de{% else %}en{% endif %}/scan"
|
||||
class="btn btn-default" target="_blank">
|
||||
{% trans "Download pretixSCAN" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{% trans "Open the app that you want to connect and optionally reset it to the original state." %}
|
||||
</li>
|
||||
<li>{% trans "Scan the following configuration code:" %}<br><br>
|
||||
<script type="text/json" data-replace-with-qr>{{ qrdata|safe }}</script><br>
|
||||
{% trans "If your app/device does not support scanning a QR code, you can also enter the following information:" %}
|
||||
@@ -17,19 +26,6 @@
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="alert alert-warning">
|
||||
<strong>
|
||||
{% blocktrans trimmed %}
|
||||
Please note that this is a new feature that currently only works for beta-stage software, such as
|
||||
pretixPOS. pretixdroid 1.x and pretixdesk 0.x are not supported by this feature. Future versions of
|
||||
pretixdroid and pretixdesk will be supported through this menu.
|
||||
{% endblocktrans %}
|
||||
</strong>
|
||||
<br><br>
|
||||
{% blocktrans trimmed %}
|
||||
To set up pretixdroid or pretixdesk, please go to the <strong>Check-in devices</strong> section of an event.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
<a href="{% url "control:organizer.devices" organizer=request.organizer.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-arrow-left"></i>
|
||||
{% trans "Device overview" %}
|
||||
|
||||
@@ -5,23 +5,12 @@
|
||||
<h1>
|
||||
{% trans "Connected devices" %}
|
||||
</h1>
|
||||
<div class="alert alert-info">
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
This menu allows you to connect hardware devices such as box office terminals or scanning terminals to
|
||||
your account.
|
||||
{% endblocktrans %}
|
||||
<strong>
|
||||
{% blocktrans trimmed %}
|
||||
Please note that this is a new feature that currently only works for beta-stage software, such as
|
||||
pretixPOS. pretixdroid 1.x and pretixdesk 0.x are not supported by this feature. Future versions of
|
||||
pretixdroid and pretixdesk will be supported through this menu.
|
||||
{% endblocktrans %}
|
||||
</strong>
|
||||
<br><br>
|
||||
{% blocktrans trimmed %}
|
||||
To set up pretixdroid or pretixdesk, please go to the <strong>Check-in devices</strong> section of an event.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
</p>
|
||||
{% if devices|length == 0 %}
|
||||
<div class="empty-collection">
|
||||
<p>
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
{% if v.variation %}
|
||||
– {{ v.variation }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% elif v.quota %}
|
||||
{% blocktrans trimmed with quota=v.quota.name %}
|
||||
Any product in quota "{{ quota }}"
|
||||
{% endblocktrans %}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.files import File
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, F, Prefetch, Q
|
||||
@@ -684,6 +685,8 @@ class QuotaView(ChartContainingView, DetailView):
|
||||
Q(Q(self.object._position_lookup) | Q(quota=self.object)) &
|
||||
Q(redeemed__lt=F('max_usages'))
|
||||
).exists()
|
||||
if self.object.closed:
|
||||
ctx['closed_and_sold_out'] = self.object._availability(ignore_closed=True)[0] <= Quota.AVAILABILITY_ORDERED
|
||||
|
||||
return ctx
|
||||
|
||||
@@ -695,6 +698,32 @@ class QuotaView(ChartContainingView, DetailView):
|
||||
except Quota.DoesNotExist:
|
||||
raise Http404(_("The requested quota does not exist."))
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_change_items', request):
|
||||
raise PermissionDenied()
|
||||
quota = self.get_object()
|
||||
if 'reopen' in request.POST:
|
||||
quota.closed = False
|
||||
quota.save(update_fields=['closed'])
|
||||
quota.log_action('pretix.event.quota.opened', user=request.user)
|
||||
messages.success(request, _('The quota has been re-opened.'))
|
||||
if 'disable' in request.POST:
|
||||
quota.closed = False
|
||||
quota.close_when_sold_out = False
|
||||
quota.save(update_fields=['closed', 'close_when_sold_out'])
|
||||
quota.log_action('pretix.event.quota.opened', user=request.user)
|
||||
quota.log_action(
|
||||
'pretix.event.quota.changed', user=self.request.user, data={
|
||||
'close_when_sold_out': False
|
||||
}
|
||||
)
|
||||
messages.success(request, _('The quota has been re-opened and will not close again.'))
|
||||
return redirect(reverse('control:event.items.quotas.show', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
'quota': quota.pk
|
||||
}))
|
||||
|
||||
|
||||
class QuotaUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Quota
|
||||
@@ -771,7 +800,8 @@ class QuotaDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['dependent'] = list(self.get_object().items.all())
|
||||
context['dependent'] = list(self.object.items.all())
|
||||
context['vouchers'] = self.object.vouchers.count()
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
@@ -1183,6 +1213,7 @@ class ItemDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['possible'] = self.is_allowed()
|
||||
context['vouchers'] = self.object.vouchers.count()
|
||||
return context
|
||||
|
||||
def is_allowed(self) -> bool:
|
||||
|
||||
@@ -17,7 +17,7 @@ from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.forms import SafeSessionWizardView
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import Event, Organizer, Quota, Team
|
||||
from pretix.base.models import Event, EventMetaValue, Organizer, Quota, Team
|
||||
from pretix.control.forms.event import (
|
||||
EventWizardBasicsForm, EventWizardCopyForm, EventWizardFoundationForm,
|
||||
)
|
||||
@@ -32,8 +32,13 @@ class EventList(PaginationMixin, ListView):
|
||||
template_name = 'pretixcontrol/events/index.html'
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.user.get_events_with_any_permission(self.request).select_related('organizer').prefetch_related(
|
||||
'_settings_objects', 'organizer___settings_objects'
|
||||
qs = self.request.user.get_events_with_any_permission(self.request).prefetch_related(
|
||||
'organizer', '_settings_objects', 'organizer___settings_objects', 'organizer__meta_properties',
|
||||
Prefetch(
|
||||
'meta_values',
|
||||
EventMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached'
|
||||
)
|
||||
).order_by('-date_from')
|
||||
|
||||
qs = qs.annotate(
|
||||
|
||||
@@ -38,7 +38,6 @@ from pretix.base.models import (
|
||||
Item, ItemVariation, LogEntry, Order, QuestionAnswer, Quota,
|
||||
generate_position_secret, generate_secret,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.orders import (
|
||||
OrderFee, OrderPayment, OrderPosition, OrderRefund,
|
||||
)
|
||||
@@ -55,6 +54,7 @@ from pretix.base.services.mail import SendMailException, render_mail
|
||||
from pretix.base.services.orders import (
|
||||
OrderChangeManager, OrderError, approve_order, cancel_order, deny_order,
|
||||
extend_order, mark_order_expired, mark_order_refunded,
|
||||
notify_user_changed_order,
|
||||
)
|
||||
from pretix.base.services.stats import order_overview
|
||||
from pretix.base.services.tickets import generate
|
||||
@@ -65,7 +65,9 @@ from pretix.base.templatetags.money import money_filter
|
||||
from pretix.base.templatetags.rich_text import markdown_compile_email
|
||||
from pretix.base.views.mixins import OrderQuestionsViewMixin
|
||||
from pretix.base.views.tasks import AsyncAction
|
||||
from pretix.control.forms.filter import EventOrderFilterForm, RefundFilterForm
|
||||
from pretix.control.forms.filter import (
|
||||
EventOrderFilterForm, OverviewFilterForm, RefundFilterForm,
|
||||
)
|
||||
from pretix.control.forms.orders import (
|
||||
CancelForm, CommentForm, ConfirmPaymentForm, ExporterForm, ExtendForm,
|
||||
MarkPaidForm, OrderContactForm, OrderLocaleForm, OrderMailForm,
|
||||
@@ -1116,7 +1118,8 @@ class InvoiceDownload(EventPermissionRequiredMixin, View):
|
||||
invoice_pdf_task.apply(args=(self.invoice.pk,))
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(self.invoice.number)
|
||||
resp['Content-Disposition'] = 'inline; filename="{}.pdf"'.format(self.invoice.number)
|
||||
resp._csp_ignore = True # Some browser's PDF readers do not work with CSP
|
||||
return resp
|
||||
|
||||
|
||||
@@ -1319,12 +1322,27 @@ class OrderModifyInformation(OrderQuestionsViewMixin, OrderView):
|
||||
only_user_visible = False
|
||||
all_optional = True
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['other_form'] = self.other_form
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def other_form(self):
|
||||
return OtherOperationsForm(prefix='other', order=self.order,
|
||||
data=self.request.POST if self.request.method == "POST" else None)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
failed = not self.save() or not self.invoice_form.is_valid()
|
||||
failed = not self.save() or not self.invoice_form.is_valid() or not self.other_form.is_valid()
|
||||
notify = self.other_form.cleaned_data['notify'] if self.other_form.is_valid() else True
|
||||
if failed:
|
||||
messages.error(self.request,
|
||||
_("We had difficulties processing your input. Please review the errors below."))
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
if notify:
|
||||
notify_user_changed_order(self.order)
|
||||
|
||||
if hasattr(self.invoice_form, 'save'):
|
||||
self.invoice_form.save()
|
||||
self.order.log_action('pretix.event.order.modified', {
|
||||
@@ -1577,21 +1595,32 @@ class OverView(EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = 'pretixcontrol/orders/overview.html'
|
||||
permission = 'can_view_orders'
|
||||
|
||||
@cached_property
|
||||
def filter_form(self):
|
||||
return OverviewFilterForm(data=self.request.GET, event=self.request.event)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data()
|
||||
|
||||
subevent = None
|
||||
if self.request.GET.get("subevent", "") != "" and self.request.event.has_subevents:
|
||||
i = self.request.GET.get("subevent", "")
|
||||
try:
|
||||
subevent = self.request.event.subevents.get(pk=i)
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
ctx['items_by_category'], ctx['total'] = order_overview(self.request.event, subevent=subevent)
|
||||
ctx['subevent_warning'] = self.request.event.has_subevents and subevent and (
|
||||
if self.filter_form.is_valid():
|
||||
ctx['items_by_category'], ctx['total'] = order_overview(
|
||||
self.request.event,
|
||||
subevent=self.filter_form.cleaned_data.get('subevent'),
|
||||
date_filter=self.filter_form.cleaned_data['date_axis'],
|
||||
date_from=self.filter_form.cleaned_data['date_from'],
|
||||
date_until=self.filter_form.cleaned_data['date_until'],
|
||||
)
|
||||
else:
|
||||
ctx['items_by_category'], ctx['total'] = order_overview(
|
||||
self.request.event,
|
||||
)
|
||||
ctx['subevent_warning'] = (
|
||||
self.request.event.has_subevents and
|
||||
self.filter_form.is_valid() and
|
||||
self.filter_form.cleaned_data.get('subevent') and
|
||||
OrderFee.objects.filter(order__event=self.request.event).exclude(value=0).exists()
|
||||
)
|
||||
ctx['filter_form'] = self.filter_form
|
||||
return ctx
|
||||
|
||||
|
||||
|
||||
@@ -9,8 +9,23 @@ _json_escapes = {
|
||||
ord('&'): '\\u0026',
|
||||
}
|
||||
|
||||
_json_escapes_attr = {
|
||||
ord('>'): '\\u003E',
|
||||
ord('<'): '\\u003C',
|
||||
ord('&'): '\\u0026',
|
||||
ord('"'): '"',
|
||||
ord("'"): ''',
|
||||
ord("="): '=',
|
||||
}
|
||||
|
||||
|
||||
@keep_lazy(six.text_type, SafeText)
|
||||
def escapejson(value):
|
||||
"""Hex encodes characters for use in a application/json type script."""
|
||||
return mark_safe(force_text(value).translate(_json_escapes))
|
||||
|
||||
|
||||
@keep_lazy(six.text_type, SafeText)
|
||||
def escapejson_attr(value):
|
||||
"""Hex encodes characters for use in a html attributw script."""
|
||||
return mark_safe(force_text(value).translate(_json_escapes_attr))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from django.conf import settings
|
||||
from django.http import StreamingHttpResponse
|
||||
|
||||
|
||||
@@ -9,3 +10,12 @@ class ChunkBasedFileResponse(StreamingHttpResponse):
|
||||
streaming_content = streaming_content.chunks(self.block_size)
|
||||
super().__init__(streaming_content, *args, **kwargs)
|
||||
self['Content-Length'] = filelike.size
|
||||
|
||||
|
||||
def get_client_ip(request):
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
if settings.TRUST_X_FORWARDED_FOR:
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0]
|
||||
return ip
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
@@ -46,61 +46,71 @@ msgstr ""
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
msgid "Contacting your bank …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
"browser and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
"page and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr ""
|
||||
|
||||
@@ -168,37 +178,37 @@ msgstr ""
|
||||
msgid "Generating messages …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
@@ -45,61 +45,71 @@ msgstr ""
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
msgid "Contacting your bank …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
"browser and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
"page and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr ""
|
||||
|
||||
@@ -167,37 +177,37 @@ msgstr ""
|
||||
msgid "Generating messages …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
@@ -45,61 +45,71 @@ msgstr ""
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
msgid "Contacting your bank …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
"browser and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
"page and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr ""
|
||||
|
||||
@@ -167,37 +177,37 @@ msgstr ""
|
||||
msgid "Generating messages …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: 2018-04-24 14:22+0000\n"
|
||||
"Last-Translator: Pernille Thorsen <perth@aarhus.dk>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -46,12 +46,23 @@ msgstr "Omsætning i alt"
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr "Kontakter Stripe …"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Kontakter Stripe …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
@@ -60,7 +71,7 @@ msgstr ""
|
||||
"der gå op til et par minutter."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Your request has been queued on the server and will now be processed. If "
|
||||
@@ -74,13 +85,14 @@ msgstr ""
|
||||
"Din forespørgsel er under behandling. Hvis der går mere end to minutter, så "
|
||||
"kontakt os eller gå tilbage og prøv igen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr "Der er sket en fejl ({code})."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
@@ -88,12 +100,12 @@ msgstr ""
|
||||
"Vi kan ikke komme i kontakt med serveren, men prøver igen. Seneste fejlkode: "
|
||||
"{code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr "Forespørgselen tog for lang tid. Prøv venligst igen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
@@ -101,11 +113,11 @@ msgstr ""
|
||||
"Vi kan ikke komme i kontakt med serveren. Prøv venligst igen. Fejlkode: "
|
||||
"{code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr "Vi behandler din bestilling …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
@@ -114,8 +126,8 @@ msgstr ""
|
||||
"Din forespørgsel bliver sendt til serveren. Hvis det tager mere end et "
|
||||
"minut, så tjek din internetforbindelse, genindlæs siden og prøv igen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr "Luk besked"
|
||||
|
||||
@@ -184,37 +196,37 @@ msgstr "Der er sket en fejl."
|
||||
msgid "Generating messages …"
|
||||
msgstr "Opretter beskeder …"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr "Ukendt fejl."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr "Ingen"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: 2019-05-01 12:13+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -47,12 +47,23 @@ msgstr "Gesamtumsatz"
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr "Kontaktiere Stripe …"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr "Gesamt"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Kontaktiere Stripe …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
@@ -61,7 +72,7 @@ msgstr ""
|
||||
"Größe der Veranstaltung kann dies einige Minuten dauern."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
@@ -72,13 +83,14 @@ msgstr ""
|
||||
"bitte oder gehen Sie in Ihrem Browser einen Schritt zurück und versuchen es "
|
||||
"erneut."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr "Ein Fehler ist aufgetreten. Fehlercode: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
@@ -86,12 +98,12 @@ msgstr ""
|
||||
"Wir können den Server aktuell nicht erreichen, versuchen es aber weiter. "
|
||||
"Letzter Fehlercode: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr "Diese Anfrage hat zu lange gedauert. Bitte erneut versuchen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
@@ -99,11 +111,11 @@ msgstr ""
|
||||
"Wir können den Server aktuell nicht erreichen. Bitte versuchen Sie es noch "
|
||||
"einmal. Fehlercode: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr "Wir verarbeiten Ihre Anfrage …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
@@ -113,8 +125,8 @@ msgstr ""
|
||||
"dauert, prüfen Sie bitte Ihre Internetverbindung. Danach können Sie diese "
|
||||
"Seite neu laden und es erneut versuchen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr "Schließen"
|
||||
|
||||
@@ -184,20 +196,20 @@ msgstr "Ein Fehler ist aufgetreten."
|
||||
msgid "Generating messages …"
|
||||
msgstr "Generiere Nachrichten…"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr "Unbekannter Fehler."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr "Diese Farbe hat einen sehr guten Kontrast und ist sehr gut zu lesen!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
"Diese Farbe hat einen ausreichenden Kontrast und wahrscheinlich gut zu lesen!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
@@ -205,19 +217,19 @@ 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:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr "Keine"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Intern einen anderen Namen verwenden"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr "Klicken zum Schließen"
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: 2019-05-01 12:12+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||
@@ -47,12 +47,23 @@ msgstr "Gesamtumsatz"
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr "Kontaktiere Stripe …"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr "Gesamt"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Kontaktiere Stripe …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
@@ -61,7 +72,7 @@ msgstr ""
|
||||
"nach Größe der Veranstaltung kann dies einige Minuten dauern."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
@@ -71,13 +82,14 @@ msgstr ""
|
||||
"verarbeitet. Wenn dies länger als zwei Minuten dauert, kontaktiere uns bitte "
|
||||
"oder gehe in deinem Browser einen Schritt zurück und versuche es erneut."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr "Ein Fehler vom Typ {code} ist aufgetreten."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
@@ -85,12 +97,12 @@ msgstr ""
|
||||
"Wir können den Server aktuell nicht erreichen, versuchen es aber weiter. "
|
||||
"Letzter Fehlercode: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr "Diese Anfrage hat zu lange gedauert. Bitte erneut versuchen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
@@ -98,11 +110,11 @@ msgstr ""
|
||||
"Wir können den Server aktuell nicht erreichen. Bitte versuche es noch "
|
||||
"einmal. Fehlercode: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr "Wir verarbeiten deine Anfrage …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
@@ -112,8 +124,8 @@ msgstr ""
|
||||
"dauert, prüfe bitte deine Internetverbindung. Danach kannst du diese Seite "
|
||||
"neu laden und es erneut versuchen."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr "Schließen"
|
||||
|
||||
@@ -183,20 +195,20 @@ msgstr "Ein Fehler ist aufgetreten."
|
||||
msgid "Generating messages …"
|
||||
msgstr "Generiere Nachrichten…"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr "Unbekannter Fehler."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr "Diese Farbe hat einen sehr guten Kontrast und ist sehr gut zu lesen!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
"Diese Farbe hat einen ausreichenden Kontrast und wahrscheinlich gut zu lesen!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
@@ -204,19 +216,19 @@ 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:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr "Keine"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Intern einen anderen Namen verwenden"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr "Klicken zum Schließen"
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+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"
|
||||
@@ -46,61 +46,71 @@ msgstr ""
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
msgid "Contacting your bank …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
"browser and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
"page and try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr ""
|
||||
|
||||
@@ -168,37 +178,37 @@ msgstr ""
|
||||
msgid "Generating messages …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: 2019-06-04 16:00+0000\n"
|
||||
"Last-Translator: ThanosTeste <testebasisth@unisystems.eu>\n"
|
||||
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -47,12 +47,23 @@ msgstr "Συνολικά κέρδη"
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr "Επικοινωνία με το Stripe …"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr "Σύνολο"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Επικοινωνία με το Stripe …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
@@ -62,7 +73,7 @@ msgstr ""
|
||||
"διαρκέσει μερικά λεπτά."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
@@ -72,13 +83,14 @@ msgstr ""
|
||||
"του. Αν αυτό διαρκεί περισσότερο από δύο λεπτά, επικοινωνήστε μαζί μας ή "
|
||||
"επιστρέψτε στο πρόγραμμα περιήγησής σας και δοκιμάστε ξανά."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr "Παρουσιάστηκε σφάλμα τύπου {code}."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
@@ -86,12 +98,12 @@ msgstr ""
|
||||
"Αυτήν τη στιγμή δεν μπορούμε να φτάσουμε στο διακομιστή, αλλά συνεχίζουμε να "
|
||||
"προσπαθούμε. Τελευταίος κωδικός σφάλματος: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr "Το αίτημα διήρκησε πολύ. Παρακαλώ προσπαθήστε ξανά."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
@@ -99,11 +111,11 @@ msgstr ""
|
||||
"Αυτήν τη στιγμή δεν μπορούμε να συνδεθούμε με το διακομιστή. Παρακαλώ "
|
||||
"προσπαθήστε ξανά. Κωδικός σφάλματος: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr "Επεξεργαζόμαστε το αίτημά σας …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
@@ -113,8 +125,8 @@ msgstr ""
|
||||
"περισσότερο από ένα λεπτό, ελέγξτε τη σύνδεσή σας στο διαδίκτυο και στη "
|
||||
"συνέχεια επαναλάβετε τη φόρτωση αυτής της σελίδας και δοκιμάστε ξανά."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr "Κλείσιμο μηνύματος"
|
||||
|
||||
@@ -185,22 +197,22 @@ msgstr "Παρουσιάστηκε σφάλμα."
|
||||
msgid "Generating messages …"
|
||||
msgstr "Δημιουργία μηνυμάτων …"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr "Αγνωστο σφάλμα."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
"Το χρώμα σας έχει μεγάλη αντίθεση και είναι πολύ εύκολο να το διαβάσετε!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
"Το χρώμα σας έχει αξιοπρεπή αντίθεση και είναι ίσως αρκετά καλό για να "
|
||||
"διαβάσετε!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
@@ -208,19 +220,19 @@ msgstr ""
|
||||
"Το χρώμα σας έχει κακή αντίθεση για κείμενο σε λευκό φόντο, επιλέξτε μια πιο "
|
||||
"σκούρα σκιά."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr "Ολα"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr "Κανένας"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr "Κάντε κλικ για να κλείσετε"
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: 2019-03-31 08:00+0000\n"
|
||||
"Last-Translator: oocf <oswaldocerna@gmail.com>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
@@ -47,12 +47,23 @@ msgstr "Ingresos totales"
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr "Contactando con Stripe…"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Contactando con Stripe…"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
@@ -61,7 +72,7 @@ msgstr ""
|
||||
"puede tomar uno o varios minutos, en dependencia del tamaño de su evento."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
msgid ""
|
||||
"Your request arrived on the server but we still wait for it to be processed. "
|
||||
"If this takes longer than two minutes, please contact us or go back in your "
|
||||
@@ -71,13 +82,14 @@ msgstr ""
|
||||
"Si toma más de dos minutos, por favor contáctenos o regrese a la página "
|
||||
"anterior en su navegador y pruebe de nuevo."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr "Ha ocurrido un error de tipo {code}."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
@@ -85,12 +97,12 @@ msgstr ""
|
||||
"Ahora mismo no podemos contactar con el servidor, pero lo seguimos "
|
||||
"intentando. El último código de error fue: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr "La solicitud ha tomado demasiado tiempo. Por favor, pruebe de nuevo."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
@@ -98,11 +110,11 @@ msgstr ""
|
||||
"Ahora mismo no podemos contactar con el servidor. Por favor, pruebe de "
|
||||
"nuevo. Código de error: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr "Estamos procesando su solicitud…"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
@@ -112,8 +124,8 @@ msgstr ""
|
||||
"minuto, por favor, revise su conexión a Internet, recargue la página y "
|
||||
"pruebe de nuevo."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr "Cerrar mensaje"
|
||||
|
||||
@@ -184,21 +196,21 @@ msgstr "Ha ocurrido un error."
|
||||
msgid "Generating messages …"
|
||||
msgstr "Generando mensajes…"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr "Error desconocido."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr "¡Tu color tiene gran contraste y es muy legible!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
"¡Tu color tiene un contraste decente y es probablemente suficientemente "
|
||||
"legible!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
@@ -206,19 +218,19 @@ 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:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr "Todos"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr "Ninguno"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Usar un nombre diferente internamente"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr "Click para cerrar"
|
||||
|
||||
|
||||
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: 2019-06-25 09:08+0000\n"
|
||||
"POT-Creation-Date: 2019-07-15 08:31+0000\n"
|
||||
"PO-Revision-Date: 2018-10-28 10:23+0000\n"
|
||||
"Last-Translator: Arnaud Vergnet <keplyx@gmail.com>\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
@@ -46,12 +46,23 @@ msgstr "Revenu total"
|
||||
msgid "Contacting Stripe …"
|
||||
msgstr "Contacter Stripe …"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:56
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:144
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:175
|
||||
msgid "Confirming your payment …"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:151
|
||||
#, fuzzy
|
||||
#| msgid "Contacting Stripe …"
|
||||
msgid "Contacting your bank …"
|
||||
msgstr "Contacter Stripe …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:39
|
||||
#: pretix/static/pretixbase/js/asynctask.js:95
|
||||
#: pretix/static/pretixbase/js/asynctask.js:105
|
||||
msgid ""
|
||||
"Your request has been queued on the server and will now be processed. "
|
||||
"Depending on the size of your event, this might take up to a few minutes."
|
||||
@@ -60,7 +71,7 @@ msgstr ""
|
||||
"taille de votre événement, cela peut prendre jusqu' à quelques minutes."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:45
|
||||
#: pretix/static/pretixbase/js/asynctask.js:101
|
||||
#: pretix/static/pretixbase/js/asynctask.js:111
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Your request has been queued on the server and will now be processed. If "
|
||||
@@ -75,13 +86,14 @@ msgstr ""
|
||||
"prend plus de deux minutes, veuillez nous contacter ou retourner dans votre "
|
||||
"navigateur et réessayer."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:66
|
||||
#: pretix/static/pretixbase/js/asynctask.js:124
|
||||
#: pretix/static/pretixbase/js/asynctask.js:76
|
||||
#: pretix/static/pretixbase/js/asynctask.js:142
|
||||
#: pretix/static/pretixbase/js/asynctask.js:147
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:23
|
||||
msgid "An error of type {code} occurred."
|
||||
msgstr "Une erreur de type {code} s'est produite."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:69
|
||||
#: pretix/static/pretixbase/js/asynctask.js:79
|
||||
msgid ""
|
||||
"We currently cannot reach the server, but we keep trying. Last error code: "
|
||||
"{code}"
|
||||
@@ -89,12 +101,12 @@ msgstr ""
|
||||
"Nous ne pouvons actuellement pas atteindre le serveur, mais nous continuons "
|
||||
"d'essayer. Dernier code d'erreur: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:115
|
||||
#: pretix/static/pretixbase/js/asynctask.js:125
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:20
|
||||
msgid "The request took to long. Please try again."
|
||||
msgstr "La requête a prit trop de temps. Veuillez réessayer."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:127
|
||||
#: pretix/static/pretixbase/js/asynctask.js:150
|
||||
#: pretix/static/pretixcontrol/js/ui/mail.js:25
|
||||
msgid ""
|
||||
"We currently cannot reach the server. Please try again. Error code: {code}"
|
||||
@@ -102,11 +114,11 @@ msgstr ""
|
||||
"Actuellement, nous ne pouvons pas atteindre le serveur. Veuillez réessayer. "
|
||||
"Code d'erreur: {code}"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:148
|
||||
#: pretix/static/pretixbase/js/asynctask.js:171
|
||||
msgid "We are processing your request …"
|
||||
msgstr "Nous traitons votre demande …"
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:156
|
||||
#: pretix/static/pretixbase/js/asynctask.js:179
|
||||
msgid ""
|
||||
"We are currently sending your request to the server. If this takes longer "
|
||||
"than one minute, please check your internet connection and then reload this "
|
||||
@@ -116,8 +128,8 @@ msgstr ""
|
||||
"d'une minute, veuillez vérifier votre connexion Internet, puis recharger "
|
||||
"cette page et réessayer."
|
||||
|
||||
#: pretix/static/pretixbase/js/asynctask.js:193
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:20
|
||||
#: pretix/static/pretixbase/js/asynctask.js:216
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:34
|
||||
msgid "Close message"
|
||||
msgstr "Fermer le message"
|
||||
|
||||
@@ -189,37 +201,37 @@ msgstr "Une erreur s'est produite."
|
||||
msgid "Generating messages …"
|
||||
msgstr "Création de messages …"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:55
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:69
|
||||
msgid "Unknown error."
|
||||
msgstr "Erreur inconnue."
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:217
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:231
|
||||
msgid "Your color has great contrast and is very easy to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:221
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:235
|
||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:225
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:239
|
||||
msgid ""
|
||||
"Your color has bad contrast for text on white background, please choose a "
|
||||
"darker shade."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:305
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:319
|
||||
msgid "All"
|
||||
msgstr "Tous"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:306
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:320
|
||||
msgid "None"
|
||||
msgstr "Aucun"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:595
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:609
|
||||
msgid "Use a different name internally"
|
||||
msgstr "Utiliser un nom différent en interne"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:652
|
||||
#: pretix/static/pretixcontrol/js/ui/main.js:666
|
||||
msgid "Click to close"
|
||||
msgstr ""
|
||||
|
||||
|
||||
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