Compare commits

..

135 Commits

Author SHA1 Message Date
Raphael Michel
951e498089 Use Stripe's new connect onboardning 2020-10-14 18:42:34 +02:00
Raphael Michel
b4a7729cb5 Fix duplicate invoice cancellation when changing free order to paid 2020-10-14 18:08:12 +02:00
Raphael Michel
f2e5e89970 Order import: Allow to reference question options by value 2020-10-14 16:29:32 +02:00
Raphael Michel
4fd773caf6 Change calendar restriction from "100 events" to "50 future events" 2020-10-14 11:39:40 +02:00
Raphael Michel
6402f0d86e Add addresses to check-in lists 2020-10-14 11:34:41 +02:00
Raphael Michel
f5d93eaffa s/WhiteList/AllowList/g 2020-10-14 11:23:47 +02:00
Raphael Michel
3f40a8e6fa Fix import of attendee addresses 2020-10-14 11:09:41 +02:00
Raphael Michel
b947467589 Update po files
[CI skip]

Signed-off-by: Raphael Michel <mail@raphaelmichel.de>
2020-10-13 18:13:07 +02:00
Raphael Michel
810f3d7d31 Minor improvements to security profiles 2020-10-13 18:02:56 +02:00
Raphael Michel
e8f3ad633a Add device security profiles (#1806) 2020-10-13 17:40:25 +02:00
Raphael Michel
301849f771 Merge pull request #1800 from pretix-translations/weblate-pretix-pretix 2020-10-13 16:30:40 +02:00
Tobias Sundgren
ee6a595e26 Translated on translate.pretix.eu (Swedish)
Currently translated at 11.0% (414 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-10-12 12:22:17 +02:00
Tobias Sundgren
980296e38a Translated on translate.pretix.eu (Swedish)
Currently translated at 10.8% (405 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-10-12 12:22:17 +02:00
Tobias Sundgren
0a62ee0e33 Translated on translate.pretix.eu (Swedish)
Currently translated at 10.6% (400 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-10-12 12:22:17 +02:00
Raphael Michel
afc1013d69 Fix infinite price adjustment loop when combining free prices, country-dependent tax rates, and vouchers 2020-10-12 12:15:58 +02:00
Raphael Michel
16cf3cec76 Add tests for device API 2020-10-12 12:15:58 +02:00
Raphael Michel
0105b9642d Add compat function for date.fromisocalendar for Python 3.6-3.7 2020-10-12 12:15:58 +02:00
Raphael Michel
3ec15fa529 Fix widget test cases 2020-10-11 20:42:35 +02:00
Raphael Michel
703eebab47 Remove tests for deleted pretixdroid code 2020-10-11 20:32:25 +02:00
Raphael Michel
3aec3a52fc Merge pull request #1805 from Chessmasterrr/patch-1
Update plugin-development documentation
2020-10-11 14:48:11 +02:00
Chessmaster
fd93cac8cf Update plugins.rst
Fixed small typo and update references
2020-10-11 13:58:01 +02:00
Raphael Michel
e139924696 Add reason based classes to events in widget 2020-10-09 16:12:05 +02:00
Raphael Michel
da725c0bff Backend forms: Do not allow to click empty labels 2020-10-09 12:19:44 +02:00
Raphael Michel
dca61447cf Fix widget bug with large number of variations 2020-10-08 16:19:48 +02:00
Raphael Michel
f54bf3f1ea Specific error message for payment_ended 2020-10-08 09:28:53 +02:00
Raphael Michel
3cef9bac26 Restrict collapsed days to large numbers 2020-10-07 15:02:12 +02:00
Raphael Michel
4f20849e4b Rewrite subquery in gift card list 2020-10-07 10:53:59 +02:00
Raphael Michel
758981fc1b Use internal name of product in OrderFilterForm 2020-10-07 10:49:20 +02:00
Raphael Michel
9b671d6370 Week calendar: Collapse days on mobile (except the current day) 2020-10-07 10:41:30 +02:00
Raphael Michel
3bfaf55094 Check-in list API: Show items in event default language 2020-10-07 10:04:26 +02:00
Raphael Michel
3708dab656 Add allow_entry_after_exit field to subevent editing 2020-10-07 09:25:53 +02:00
Raphael Michel
14ad7716bd Fix missing copy button for add-ons if only system fields match 2020-10-06 18:45:53 +02:00
Raphael Michel
985d3c3993 Add date column to web-based check-in list 2020-10-06 18:45:53 +02:00
Raphael Michel
fa2222e629 Remove pretixdroid code 2020-10-06 18:45:53 +02:00
Raphael Michel
13eabdd7f4 Fix missing date column in list of refunds 2020-10-06 18:45:53 +02:00
Raphael Michel
4fd748e6d9 Merge pull request #1796 from pretix-translations/weblate-pretix-pretix 2020-10-06 16:00:19 +02:00
Tobias Sundgren
f48ded0165 Translated on translate.pretix.eu (Swedish)
Currently translated at 8.1% (305 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-10-06 15:02:14 +02:00
Tobias Sundgren
903ea09140 Translated on translate.pretix.eu (Swedish)
Currently translated at 8.1% (304 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-10-06 15:02:14 +02:00
Maarten van den Berg
fadc610b8e Translated on translate.pretix.eu (Dutch (informal))
Currently translated at 100.0% (3762 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl_Informal/

powered by weblate
2020-10-06 15:02:14 +02:00
Maarten van den Berg
ac4b8a392b Translated on translate.pretix.eu (Dutch)
Currently translated at 100.0% (3762 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2020-10-06 15:02:14 +02:00
ethan.wang
22d986a709 Translated on translate.pretix.eu (Chinese (Simplified))
Currently translated at 82.4% (3100 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/zh_Hans/

powered by weblate
2020-10-06 15:02:14 +02:00
Martin Gross
bca34145f1 Translated on translate.pretix.eu (Danish)
Currently translated at 42.6% (1603 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2020-10-06 15:02:14 +02:00
Mie Frydensbjerg
97af6f7311 Translated on translate.pretix.eu (Danish)
Currently translated at 42.6% (1603 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2020-10-06 15:02:14 +02:00
Martin Gross
67156a67aa Translated on translate.pretix.eu (Danish)
Currently translated at 42.6% (1602 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2020-10-06 15:02:14 +02:00
Raphael Michel
4ed872d4ef Calendar stuff is hard 2020-10-06 15:02:05 +02:00
Martin Gross
5cd6cba0a2 Fix accidential removal of gitcard-filter 2020-10-06 14:46:53 +02:00
Martin Gross
72bb5bd177 Only include Confirmed and Refunded Payments/completed Refunds in Giftcard-report 2020-10-06 14:30:39 +02:00
Raphael Michel
d392e14a96 Fix date() usage 2020-10-06 12:50:37 +02:00
Raphael Michel
d7459b3b83 Fix years with 52 weeks 2020-10-06 12:49:02 +02:00
Martin Gross
b4778b5845 Allow to unselect product or quota from voucher (#1799) 2020-10-06 09:08:15 +02:00
Raphael Michel
5a09759cb9 Fix *yet* another time range issue 2020-10-05 17:39:41 +02:00
Raphael Michel
2fbaa90d76 Clarify docstring 2020-10-05 17:33:19 +02:00
Raphael Michel
93f10d33a9 Fix breakpoints of calendar week selection 2020-10-05 17:32:12 +02:00
Raphael Michel
e9a972ad60 Show dates in calendar week selection 2020-10-05 17:29:19 +02:00
Raphael Michel
a31f0c1bc8 Fix one more bug in calendar view 2020-10-05 17:29:11 +02:00
Raphael Michel
1b0c2f3bb7 Fix bug in previous commit 2020-10-05 17:17:28 +02:00
Raphael Michel
766428c469 Improve support for cross-midnight time slots 2020-10-05 17:14:49 +02:00
Raphael Michel
d85583f70a Fix missing field description 2020-10-05 17:13:39 +02:00
Raphael Michel
ee801bd717 Safety guard against unpaid giftcards 2020-10-05 16:09:24 +02:00
Martin Gross
af0e8ec992 Fix test, Ref: 3cbcf663e5 2020-10-05 13:45:53 +02:00
Raphael Michel
bc3325c1cb Order overview PDF: Print net and gross 2020-10-02 16:45:47 +02:00
Martin Gross
753c331887 Shutting up isort 2020-10-02 14:04:22 +02:00
Martin Gross
cfc9055ec1 Fix giftcard API doc 2020-10-02 13:58:19 +02:00
Raphael Michel
c131a2ac3a Import: Do not allow duplicate secrets even across events 2020-10-02 10:29:27 +02:00
Raphael Michel
17fe3355d1 pretixPOS: ZVT support 2020-09-29 19:10:48 +02:00
Martin Gross
0381d42d41 Fix flag for Swedish language (fixes #1795) 2020-09-29 11:11:25 +02:00
Raphael Michel
b73db911e9 Add profile OAuth scope 2020-09-28 16:11:43 +02:00
Raphael Michel
1f3d4a2810 Fix name finding in placeholders 2020-09-28 16:11:30 +02:00
Raphael Michel
3cbcf663e5 OAuth: Add profile-only access 2020-09-28 16:01:59 +02:00
Raphael Michel
ae0637a3d6 Merge pull request #1789 from pretix-translations/weblate-pretix-pretix 2020-09-28 12:15:22 +02:00
Raphael Michel
a6a9c08a0a Translated on translate.pretix.eu (German)
Currently translated at 99.9% (3761 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2020-09-28 12:15:08 +02:00
Raphael Michel
f3b3d0b8f7 Translated on translate.pretix.eu (German (informal))
Currently translated at 99.9% (3761 of 3762 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2020-09-28 12:14:57 +02:00
Raphael Michel
9490f20a6c Revert "Do not allow to cancel gift card positions"
This reverts commit 951e99d0da.
2020-09-28 12:13:04 +02:00
Raphael Michel
4555a917b2 Update po files
[CI skip]

Signed-off-by: Raphael Michel <mail@raphaelmichel.de>
2020-09-28 12:10:15 +02:00
Raphael Michel
951e99d0da Do not allow to cancel gift card positions 2020-09-28 11:51:06 +02:00
Raphael Michel
d0b002cf0c Issue gift cards after order change 2020-09-28 11:48:55 +02:00
Felix Rindt
4fb0b948ec Add name scheme with salutation (#1779) 2020-09-28 11:41:59 +02:00
Felix Rindt
2384478b45 Support required-if and display-dependency for more elements (#1788) 2020-09-28 10:42:03 +02:00
Raphael Michel
f3a2d0cb03 Merge pull request #1787 from pretix-translations/weblate-pretix-pretix 2020-09-28 09:24:07 +02:00
Maarten van den Berg
1b11d88442 Translated on translate.pretix.eu (Dutch (informal))
Currently translated at 100.0% (3757 of 3757 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl_Informal/

powered by weblate
2020-09-28 07:00:13 +02:00
Maarten van den Berg
954951ddfa Translated on translate.pretix.eu (Dutch)
Currently translated at 100.0% (3757 of 3757 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2020-09-28 07:00:12 +02:00
Raphael Michel
c01b96bdfc Allow to sort list of quotas 2020-09-25 19:08:42 +02:00
Raphael Michel
c78e88a1ba Allow to create devices through the API (#1785) 2020-09-25 18:16:18 +02:00
Raphael Michel
4cb18218b2 Do not show event time on invoice 2020-09-25 18:01:50 +02:00
Raphael Michel
450d017c32 Order API: Add `send_email` parameter to mark_paid and
payments/confirm
2020-09-25 15:12:06 +02:00
Raphael Michel
655977e33d Fix typo 2020-09-24 12:55:51 +02:00
Raphael Michel
0cb0620df0 Fix crash from previous deployment 2020-09-24 12:36:00 +02:00
Raphael Michel
c8bf069650 Merge pull request #1784 from pretix-translations/weblate-pretix-pretix 2020-09-24 12:16:28 +02:00
Raphael Michel
e65087fd68 Translated on translate.pretix.eu (German (informal))
Currently translated at 100.0% (3757 of 3757 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2020-09-24 12:16:16 +02:00
Raphael Michel
d67d389b9d Translated on translate.pretix.eu (German)
Currently translated at 100.0% (3757 of 3757 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2020-09-24 12:16:16 +02:00
Raphael Michel
0e805e50f9 Widget: consistent rendering of date ranges 2020-09-24 12:15:54 +02:00
Raphael Michel
a4d133731e Update po files
[CI skip]

Signed-off-by: Raphael Michel <mail@raphaelmichel.de>
2020-09-24 10:59:11 +02:00
Raphael Michel
c74e7fd4fb Show time slot end time in calendars 2020-09-24 10:58:48 +02:00
Raphael Michel
0e405d2327 Widget: Align wording with standalone calendar 2020-09-24 10:58:48 +02:00
Raphael Michel
035c707427 Calendar: Show fully booked instead of sold out for free events 2020-09-24 10:58:48 +02:00
Raphael Michel
787e7ec993 Merge pull request #1783 from pretix-translations/weblate-pretix-pretix 2020-09-24 10:58:38 +02:00
Svyatoslav
09a9b4a456 Translated on translate.pretix.eu (Russian)
Currently translated at 78.1% (100 of 128 strings)

Translation: pretix/pretix (frontend)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/ru/

powered by weblate
2020-09-23 19:00:12 +02:00
Svyatoslav
e2547c2761 Translated on translate.pretix.eu (Russian)
Currently translated at 29.7% (1116 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ru/

powered by weblate
2020-09-23 19:00:12 +02:00
Martin Gross
c7b2baf40f Correct file type for shredder export zip (Fixes #1781, Z#153584) 2020-09-23 13:41:47 +02:00
Felix Rindt
59595c9db8 Add setting to disable copy-answers-button (#1778) 2020-09-22 18:09:44 +02:00
Nils Schneider
2f8baecd68 Fix #1127 -- Set loglevel from configfile (#1777) 2020-09-22 17:40:56 +02:00
Raphael Michel
a76f74b161 Download reminders: Fix incomplete only() call 2020-09-21 18:26:38 +02:00
Raphael Michel
f2518101ef Fix broken test after deprecation of pretixdroid 2020-09-21 18:23:25 +02:00
Raphael Michel
ec667545e8 Fix crash/bug in order data export 2020-09-21 18:23:25 +02:00
Raphael Michel
afb789226c Webhooks: Fix crash if object was deleted in meantime 2020-09-21 18:23:25 +02:00
Felix Rindt
bca7a6db93 Mail service: Allow to attach arbitrary cached files (#1774) 2020-09-21 17:45:29 +02:00
Felix Rindt
429ad4da37 Refactor primary color to settings variable (#1775) 2020-09-21 17:44:43 +02:00
Raphael Michel
cd6e6004af Merge pull request #1773 from pretix-translations/weblate-pretix-pretix 2020-09-21 17:43:59 +02:00
Tobias Sundgren
e9d5665a3d Translated on translate.pretix.eu (Swedish)
Currently translated at 7.0% (262 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-09-19 20:00:13 +02:00
Tobias Sundgren
4cbc30a7ea Translated on translate.pretix.eu (Swedish)
Currently translated at 6.9% (261 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Tobias Sundgren
2b0388c2ee Translated on translate.pretix.eu (Swedish)
Currently translated at 5.8% (218 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Tobias Sundgren
06b8826e57 Translated on translate.pretix.eu (Swedish)
Currently translated at 100.0% (128 of 128 strings)

Translation: pretix/pretix (frontend)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Tobias Sundgren
7c6f0f45a3 Translated on translate.pretix.eu (Swedish)
Currently translated at 5.7% (213 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Tobias Sundgren
93399f51b3 Translated on translate.pretix.eu (Swedish)
Currently translated at 100.0% (128 of 128 strings)

Translation: pretix/pretix (frontend)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Pernilla Näsfors Östmar
87bd54b233 Translated on translate.pretix.eu (Swedish)
Currently translated at 100.0% (128 of 128 strings)

Translation: pretix/pretix (frontend)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Tobias Sundgren
3fb237f434 Translated on translate.pretix.eu (Swedish)
Currently translated at 5.6% (212 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2020-09-18 18:20:26 +02:00
Maarten van den Berg
d7640d25f5 Translated on translate.pretix.eu (Dutch (informal))
Currently translated at 100.0% (3756 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl_Informal/

powered by weblate
2020-09-18 18:20:26 +02:00
Maarten van den Berg
1669d3f5c7 Translated on translate.pretix.eu (Dutch)
Currently translated at 100.0% (3756 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2020-09-18 18:20:26 +02:00
Maarten van den Berg
5aa3f3e772 Translated on translate.pretix.eu (Dutch)
Currently translated at 99.6% (3741 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/nl/

powered by weblate
2020-09-18 18:20:26 +02:00
Martin Gross
b7a2f0257f Translated on translate.pretix.eu (French)
Currently translated at 80.5% (103 of 128 strings)

Translation: pretix/pretix (frontend)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/fr/

powered by weblate
2020-09-18 18:20:26 +02:00
Martin Gross
5c0f29f959 Translated on translate.pretix.eu (French)
Currently translated at 61.2% (2297 of 3756 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2020-09-18 18:20:26 +02:00
Raphael Michel
59655dca82 Fix redemption of multiple gift cards 2020-09-18 18:20:08 +02:00
Raphael Michel
af2b4ebb4b Properly deprecate pretixdroid 2020-09-18 16:28:19 +02:00
Martin Gross
d5b3528f92 Localize Stripe Elements to Order Page Language 2020-09-18 16:26:10 +02:00
Martin Gross
0a1b41235b Add Seat to Order Data Export - but better 2020-09-18 16:25:49 +02:00
Felix Rindt
8ca544064b Fix #1759: order import increasing positionids (#1776) 2020-09-18 16:16:33 +02:00
Raphael Michel
1e2b305376 Quota and check-in list list: Include time of subevent 2020-09-18 13:12:04 +02:00
Raphael Michel
bfa20e995a Order API: Include ID of check-in 2020-09-18 13:12:04 +02:00
Martin Gross
e7fd0f116b Add Seat to Order Data Export 2020-09-17 09:53:26 +02:00
Raphael Michel
e836da09cd Fix bug in a combination of timeouts and custom auth backends 2020-09-16 18:09:53 +02:00
Raphael Michel
22c6553a48 Fix API for organizers and events with a . in their slug 2020-09-16 16:37:55 +02:00
pretix translation bot
ea5fc3df40 Translations update from Weblate (#1772)
Co-authored-by: Martin Gross <martin@pc-coholic.de>
2020-09-15 10:38:28 +02:00
pretix translation bot
7977b6dc15 Translations update from Weblate (#1771)
Co-authored-by: Mie Frydensbjerg <mif@aarhus.dk>
Co-authored-by: Maarten van den Berg <maartenberg1@gmail.com>
2020-09-15 09:55:20 +02:00
Raphael Michel
59df5fe052 Fix manifest config 2020-09-14 19:00:29 +02:00
Raphael Michel
c4e00e7601 Bump to 3.12.0.dev0 2020-09-14 18:23:42 +02:00
174 changed files with 28093 additions and 28719 deletions

View File

@@ -97,6 +97,9 @@ Example::
``csp_log``
Log violations of the Content Security Policy (CSP). Defaults to ``on``.
``loglevel``
Set console and file loglevel (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` or ``CRITICAL``). Defaults to ``INFO``.
Locale settings
---------------

View File

@@ -25,7 +25,7 @@ Obtaining an authorization grant
--------------------------------
To authorize a new user, link or redirect them to the ``authorize`` endpoint, passing your client ID as a query
parameter. Additionally, you can pass a scope (currently either ``read``, ``write``, or ``read write``)
parameter. Additionally, you can pass a scope (currently either ``read``, ``write``, ``read write`` or ``profile``)
and an URL the user should be redirected to after successful or failed authorization. You also need to pass the
``response_type`` parameter with a value of ``code``. Example::
@@ -47,11 +47,9 @@ You will need this ``code`` parameter to perform the next step.
On a failed registration, a query string like ``?error=access_denied`` will be appended to the redirection URL.
.. note:: In this step, the user is allowed to restrict your access to certain organizer accounts. If you try to
re-authenticate the user later, the user might be instantly redirected back to you if authorization is already
given and would therefore be unable to review their organizer restriction settings. You can append the
``approval_prompt=force`` query parameter if you want to make sure the user actively needs to confirm the
authorization.
.. note:: By default, the user is asked to give permission on every call to this URL. If you **only** request the
``profile`` scope, i.e. no access to organizer data, you can pass the ``approval_prompt=auto`` parameter
to skip user interaction on subsequen calls.
Getting an access token
-----------------------
@@ -193,10 +191,11 @@ If you need the user's meta data, you can fetch it here:
Content-Type: application/json
{
email: "admin@localhost",
fullname: "John Doe",
locale: "de",
timezone: "Europe/Berlin"
"email": "admin@localhost",
"fullname": "John Doe",
"locale": "de",
"is_staff": false,
"timezone": "Europe/Berlin"
}
:statuscode 200: no error

View File

@@ -0,0 +1,224 @@
.. spelling:: fullname
.. _`rest-devices`:
Devices
=======
See also :ref:`rest-deviceauth`.
Device resource
----------------
The device resource contains the following public fields:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
device_id integer Internal ID of the device within this organizer
unique_serial string Unique identifier of this device
name string Device name
all_events boolean Whether this device has access to all events
limit_events list List of event slugs this device has access to
hardware_brand string Device hardware manufacturer (read-only)
hardware_model string Device hardware model (read-only)
software_brand string Device software product (read-only)
software_version string Device software version (read-only)
created datetime Creation time
initialized datetime Time of initialization (or ``null``)
initialization_token string Token for initialization
revoked boolean Whether this device no longer has access
security_profile string The name of a supported security profile restricting API access
===================================== ========================== =======================================================
Device endpoints
----------------
.. http:get:: /api/v1/organizers/(organizer)/devices/
Returns a list of all devices within a given organizer.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/devices/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"device_id": 1,
"unique_serial": "UOS3GNZ27O39V3QS",
"initialization_token": "frkso3m2w58zuw70",
"all_events": false,
"limit_events": [
"museum"
],
"revoked": false,
"name": "Scanner",
"created": "2020-09-18T14:17:40.971519Z",
"initialized": "2020-09-18T14:17:44.190021Z",
"security_profile": "full",
"hardware_brand": "Zebra",
"hardware_model": "TC25",
"software_brand": "pretixSCAN",
"software_version": "1.5.1"
}
]
}
:query integer page: The page number in case of a multi-page result set, default is 1
:param organizer: The ``slug`` field of the organizer to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/devices/(device_id)/
Returns information on one device, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/devices/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"device_id": 1,
"unique_serial": "UOS3GNZ27O39V3QS",
"initialization_token": "frkso3m2w58zuw70",
"all_events": false,
"limit_events": [
"museum"
],
"revoked": false,
"name": "Scanner",
"created": "2020-09-18T14:17:40.971519Z",
"initialized": "2020-09-18T14:17:44.190021Z",
"security_profile": "full",
"hardware_brand": "Zebra",
"hardware_model": "TC25",
"software_brand": "pretixSCAN",
"software_version": "1.5.1"
}
:param organizer: The ``slug`` field of the organizer to fetch
:param device_id: The ``device_id`` field of the device to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
.. http:post:: /api/v1/organizers/(organizer)/devices/
Creates a new device
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/devices/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"name": "Scanner",
"all_events": true,
"limit_events": [],
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"device_id": 1,
"unique_serial": "UOS3GNZ27O39V3QS",
"initialization_token": "frkso3m2w58zuw70",
"all_events": true,
"limit_events": [],
"revoked": false,
"name": "Scanner",
"created": "2020-09-18T14:17:40.971519Z",
"security_profile": "full",
"initialized": null
"hardware_brand": null,
"hardware_model": null,
"software_brand": null,
"software_version": null
}
:param organizer: The ``slug`` field of the organizer to create a device for
:statuscode 201: no error
:statuscode 400: The device could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
.. http:patch:: /api/v1/organizers/(organizer)/devices/(device_id)/
Update a device.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/devices/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 94
{
"name": "Foo"
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"name": "Foo",
...
}
:param organizer: The ``slug`` field of the organizer to modify
:param device_id: The ``device_id`` field of the deviec to modify
:statuscode 200: no error
:statuscode 400: The device could not be modified due to invalid submitted data
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.

View File

@@ -209,14 +209,15 @@ Endpoints
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/giftcards/1/transact/ HTTP/1.1
POST /api/v1/organizers/bigevents/giftcards/1/transact/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 94
Content-Length: 79
{
"value": "2.00"
"value": "2.00",
"text": "Optional value explaining the transaction"
}
**Example response**:

View File

@@ -24,6 +24,7 @@ Resources and endpoints
giftcards
carts
teams
devices
webhooks
seatingplans
billing_invoices

View File

@@ -201,6 +201,7 @@ addon_to integer Internal ID of
subevent integer ID of the date inside an event series this position belongs to (or ``null``).
pseudonymization_id string A random ID, e.g. for use in lead scanning apps
checkins list of objects List of check-ins with this ticket
├ id integer Internal ID of the check-in event
├ list integer Internal ID of the check-in list
├ datetime datetime Time of check-in
├ type string Type of scan (defaults to ``entry``)
@@ -1029,6 +1030,10 @@ Creating orders
Order state operations
----------------------
.. versionchanged:: 3.12
The ``mark_paid`` operation now takes a ``send_email`` parameter.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/mark_paid/
Marks a pending or expired order as successfully paid.
@@ -1040,6 +1045,11 @@ Order state operations
POST /api/v1/organizers/bigevents/events/sampleconf/orders/ABC12/mark_paid/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"send_email": true
}
**Example response**:
@@ -1722,6 +1732,10 @@ Order payment endpoints
Payments can now be created through the API.
.. versionchanged:: 3.12
The ``confirm`` operation now takes a ``send_email`` parameter.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/payments/
Returns a list of all payments for an order.
@@ -1822,7 +1836,10 @@ Order payment endpoints
Accept: application/json, text/javascript
Content-Type: application/json
{"force": false}
{
"send_email": true,
"force": false
}
**Example response**:

View File

@@ -136,7 +136,7 @@ in the ``installed`` method::
pass # Your code here
Note that ``installed`` will *not* be called if the plugin in indirectly activated for an event
Note that ``installed`` will *not* be called if the plugin is indirectly activated for an event
because the event is created with settings copied from another event.
Views
@@ -151,8 +151,8 @@ your Django app label.
with checking that the calling user is logged in, has appropriate permissions,
etc. We plan on providing native support for this in a later version.
.. _Django app: https://docs.djangoproject.com/en/1.7/ref/applications/
.. _signal dispatcher: https://docs.djangoproject.com/en/1.7/topics/signals/
.. _namespace packages: http://legacy.python.org/dev/peps/pep-0420/
.. _Django app: https://docs.djangoproject.com/en/3.0/ref/applications/
.. _signal dispatcher: https://docs.djangoproject.com/en/3.0/topics/signals/
.. _namespace packages: https://legacy.python.org/dev/peps/pep-0420/
.. _entry point: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#locating-plugins
.. _cookiecutter: https://cookiecutter.readthedocs.io/en/latest/

View File

@@ -3,6 +3,7 @@ include README.rst
recursive-include pretix/static *
recursive-include pretix/static.dist *
recursive-include pretix/locale *
recursive-include pretix/helpers/locale *
recursive-include pretix/base/templates *
recursive-include pretix/control/templates *
recursive-include pretix/presale/templates *

View File

@@ -1 +1 @@
__version__ = "3.11.0"
__version__ = "3.12.0.dev0"

View File

@@ -3,6 +3,9 @@ from django_scopes import scopes_disabled
from rest_framework import exceptions
from rest_framework.authentication import TokenAuthentication
from pretix.api.auth.devicesecurity import (
DEVICE_SECURITY_PROFILES, FullAccessSecurityProfile,
)
from pretix.base.models import Device
@@ -25,3 +28,11 @@ class DeviceTokenAuthentication(TokenAuthentication):
raise exceptions.AuthenticationFailed('Device access has been revoked.')
return AnonymousUser(), device
def authenticate(self, request):
r = super().authenticate(request)
if r and isinstance(r[1], Device):
profile = DEVICE_SECURITY_PROFILES.get(r[1].security_profile, FullAccessSecurityProfile)
if not profile.is_allowed(request):
raise exceptions.PermissionDenied('Request denied by device security profile.')
return r

View File

@@ -0,0 +1,112 @@
from django.utils.translation import ugettext_lazy as _
class FullAccessSecurityProfile:
identifier = 'full'
verbose_name = _('Full access')
def is_allowed(self, request):
return True
class AllowListSecurityProfile:
allowlist = tuple()
def is_allowed(self, request):
key = (request.method, f"{request.resolver_match.namespace}:{request.resolver_match.url_name}")
return key in self.allowlist
class PretixScanSecurityProfile(AllowListSecurityProfile):
identifier = 'pretixscan'
verbose_name = _('pretixSCAN')
allowlist = (
('GET', 'api-v1:version'),
('GET', 'api-v1:device.update'),
('GET', 'api-v1:device.revoke'),
('GET', 'api-v1:event-list'),
('GET', 'api-v1:event-detail'),
('GET', 'api-v1:subevent-list'),
('GET', 'api-v1:subevent-detail'),
('GET', 'api-v1:itemcategory-list'),
('GET', 'api-v1:item-list'),
('GET', 'api-v1:question-list'),
('GET', 'api-v1:badgelayout-list'),
('GET', 'api-v1:badgeitem-list'),
('GET', 'api-v1:checkinlist-list'),
('GET', 'api-v1:checkinlist-status'),
('GET', 'api-v1:checkinlistpos-list'),
('POST', 'api-v1:checkinlistpos-redeem'),
('GET', 'api-v1:order-list'),
('GET', 'api-v1:event.settings'),
)
class PretixScanNoSyncSecurityProfile(AllowListSecurityProfile):
identifier = 'pretixscan_online_kiosk'
verbose_name = _('pretixSCAN (kiosk mode, online only)')
allowlist = (
('GET', 'api-v1:version'),
('GET', 'api-v1:device.update'),
('GET', 'api-v1:device.revoke'),
('GET', 'api-v1:event-list'),
('GET', 'api-v1:event-detail'),
('GET', 'api-v1:subevent-list'),
('GET', 'api-v1:subevent-detail'),
('GET', 'api-v1:itemcategory-list'),
('GET', 'api-v1:item-list'),
('GET', 'api-v1:question-list'),
('GET', 'api-v1:badgelayout-list'),
('GET', 'api-v1:badgeitem-list'),
('GET', 'api-v1:checkinlist-list'),
('GET', 'api-v1:checkinlist-status'),
('POST', 'api-v1:checkinlistpos-redeem'),
('GET', 'api-v1:event.settings'),
)
class PretixPosSecurityProfile(AllowListSecurityProfile):
identifier = 'pretixpos'
verbose_name = _('pretixPOS')
allowlist = (
('GET', 'api-v1:version'),
('GET', 'api-v1:device.update'),
('GET', 'api-v1:device.revoke'),
('GET', 'api-v1:event-list'),
('GET', 'api-v1:event-detail'),
('GET', 'api-v1:subevent-list'),
('GET', 'api-v1:subevent-detail'),
('GET', 'api-v1:itemcategory-list'),
('GET', 'api-v1:item-list'),
('GET', 'api-v1:question-list'),
('GET', 'api-v1:quota-list'),
('GET', 'api-v1:taxrule-list'),
('GET', 'api-v1:ticketlayout-list'),
('GET', 'api-v1:ticketlayoutitem-list'),
('GET', 'api-v1:order-list'),
('POST', 'api-v1:order-list'),
('GET', 'api-v1:order-detail'),
('DELETE', 'api-v1:orderposition-detail'),
('POST', 'api-v1:order-mark_canceled'),
('POST', 'api-v1:orderrefund-list'),
('POST', 'api-v1:orderrefund-done'),
('POST', 'api-v1:cartposition-list'),
('DELETE', 'api-v1:cartposition-detail'),
('GET', 'api-v1:giftcard-list'),
('POST', 'api-v1:giftcard-transact'),
('POST', 'plugins:pretix_posbackend:posreceipt-list'),
('POST', 'plugins:pretix_posbackend:posclosing-list'),
('POST', 'plugins:pretix_posbackend:posdebugdump-list'),
('POST', 'plugins:pretix_posbackend:stripeterminal.token'),
('GET', 'api-v1:event.settings'),
)
DEVICE_SECURITY_PROFILES = {
k.identifier: k() for k in (
FullAccessSecurityProfile,
PretixScanSecurityProfile,
PretixScanNoSyncSecurityProfile,
PretixPosSecurityProfile,
)
}

View File

@@ -84,3 +84,15 @@ class EventCRUDPermission(EventPermission):
return False
return True
class ProfilePermission(BasePermission):
def has_permission(self, request, view):
if not request.user.is_authenticated:
return False
if isinstance(request.auth, OAuthAccessToken):
if not (request.auth.allow_scopes(['read']) or request.auth.allow_scopes(['profile'])) and request.method in SAFE_METHODS:
return False
return True

View File

@@ -9,7 +9,7 @@ from oauth2_provider.settings import oauth2_settings
class Validator(OAuth2Validator):
def save_authorization_code(self, client_id, code, request, *args, **kwargs):
if not getattr(request, 'organizers', None):
if not getattr(request, 'organizers', None) and request.scopes != ['profile']:
raise FatalClientError('No organizers selected.')
expires = timezone.now() + timedelta(
@@ -18,7 +18,8 @@ class Validator(OAuth2Validator):
expires=expires, redirect_uri=request.redirect_uri,
scope=" ".join(request.scopes))
g.save()
g.organizers.add(*request.organizers.all())
if request.scopes != ['profile']:
g.organizers.add(*request.organizers.all())
def validate_code(self, client_id, code, client, request, *args, **kwargs):
try:
@@ -34,12 +35,14 @@ class Validator(OAuth2Validator):
return False
def _create_access_token(self, expires, request, token, source_refresh_token=None):
if not getattr(request, 'organizers', None) and not getattr(source_refresh_token, 'access_token'):
if not getattr(request, 'organizers', None) and not getattr(source_refresh_token, 'access_token', None) and token["scope"] != 'profile':
raise FatalClientError('No organizers selected.')
if hasattr(request, 'organizers'):
orgs = list(request.organizers.all())
else:
orgs = list(source_refresh_token.access_token.organizers.all())
if token['scope'] != 'profile':
if hasattr(request, 'organizers'):
orgs = list(request.organizers.all())
else:
orgs = list(source_refresh_token.access_token.organizers.all())
access_token = super()._create_access_token(expires, request, token, source_refresh_token=None)
access_token.organizers.add(*orgs)
if token['scope'] != 'profile':
access_token.organizers.add(*orgs)
return access_token

View File

@@ -122,7 +122,7 @@ class AnswerSerializer(I18nAwareModelSerializer):
class CheckinSerializer(I18nAwareModelSerializer):
class Meta:
model = Checkin
fields = ('datetime', 'list', 'auto_checked_in', 'type')
fields = ('id', 'datetime', 'list', 'auto_checked_in', 'type')
class OrderDownloadsField(serializers.Field):

View File

@@ -9,7 +9,8 @@ from pretix.api.serializers.i18n import I18nAwareModelSerializer
from pretix.api.serializers.order import CompatibleJSONField
from pretix.base.auth import get_auth_backends
from pretix.base.models import (
GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite, User,
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
User,
)
from pretix.base.models.seating import SeatingPlanLayoutValidator
from pretix.base.services.mail import SendMailException, mail
@@ -66,9 +67,6 @@ class EventSlugField(serializers.SlugRelatedField):
class TeamSerializer(serializers.ModelSerializer):
limit_events = EventSlugField(slug_field='slug', many=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class Meta:
model = Team
fields = (
@@ -86,6 +84,28 @@ class TeamSerializer(serializers.ModelSerializer):
return data
class DeviceSerializer(serializers.ModelSerializer):
limit_events = EventSlugField(slug_field='slug', many=True)
device_id = serializers.IntegerField(read_only=True)
unique_serial = serializers.CharField(read_only=True)
hardware_brand = serializers.CharField(read_only=True)
hardware_model = serializers.CharField(read_only=True)
software_brand = serializers.CharField(read_only=True)
software_version = serializers.CharField(read_only=True)
created = serializers.DateTimeField(read_only=True)
revoked = serializers.BooleanField(read_only=True)
initialized = serializers.DateTimeField(read_only=True)
initialization_token = serializers.DateTimeField(read_only=True)
class Meta:
model = Device
fields = (
'device_id', 'unique_serial', 'initialization_token', 'all_events', 'limit_events',
'revoked', 'name', 'created', 'initialized', 'hardware_brand', 'hardware_model',
'software_brand', 'software_version', 'security_profile'
)
class TeamInviteSerializer(serializers.ModelSerializer):
class Meta:
model = TeamInvite

View File

@@ -21,6 +21,7 @@ orga_router.register(r'webhooks', webhooks.WebHookViewSet)
orga_router.register(r'seatingplans', organizer.SeatingPlanViewSet)
orga_router.register(r'giftcards', organizer.GiftCardViewSet)
orga_router.register(r'teams', organizer.TeamViewSet)
orga_router.register(r'devices', organizer.DeviceViewSet)
team_router = routers.DefaultRouter()
team_router.register(r'members', organizer.TeamMemberViewSet)
@@ -44,7 +45,7 @@ event_router.register(r'checkinlists', checkin.CheckinListViewSet)
event_router.register(r'cartpositions', cart.CartPositionViewSet)
checkinlist_router = routers.DefaultRouter()
checkinlist_router.register(r'positions', checkin.CheckinListPositionViewSet)
checkinlist_router.register(r'positions', checkin.CheckinListPositionViewSet, basename='checkinlistpos')
question_router = routers.DefaultRouter()
question_router.register(r'options', item.QuestionOptionViewSet)

View File

@@ -18,6 +18,7 @@ from pretix.api.serializers.item import QuestionSerializer
from pretix.api.serializers.order import CheckinListOrderPositionSerializer
from pretix.api.views import RichOrderingFilter
from pretix.api.views.order import OrderPositionFilter
from pretix.base.i18n import language
from pretix.base.models import (
Checkin, CheckinList, Event, Order, OrderPosition,
)
@@ -87,73 +88,74 @@ class CheckinListViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['GET'])
def status(self, *args, **kwargs):
clist = self.get_object()
cqs = Checkin.objects.filter(
position__order__event=clist.event,
position__order__status__in=[Order.STATUS_PAID] + ([Order.STATUS_PENDING] if clist.include_pending else []),
list=clist
)
pqs = OrderPosition.objects.filter(
order__event=clist.event,
order__status__in=[Order.STATUS_PAID] + ([Order.STATUS_PENDING] if clist.include_pending else []),
)
if clist.subevent:
pqs = pqs.filter(subevent=clist.subevent)
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))
with language(self.request.event.settings.locale):
clist = self.get_object()
cqs = Checkin.objects.filter(
position__order__event=clist.event,
position__order__status__in=[Order.STATUS_PAID] + ([Order.STATUS_PENDING] if clist.include_pending else []),
list=clist
)
pqs = OrderPosition.objects.filter(
order__event=clist.event,
order__status__in=[Order.STATUS_PAID] + ([Order.STATUS_PENDING] if clist.include_pending else []),
)
if clist.subevent:
pqs = pqs.filter(subevent=clist.subevent)
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 = {
'event': {
'name': str(ev.name),
},
'checkin_count': cqs.count(),
'position_count': pqs.count()
}
op_by_item = {
p['item']: p['cnt']
for p in pqs.order_by().values('item').annotate(cnt=Count('id'))
}
op_by_variation = {
p['variation']: p['cnt']
for p in pqs.order_by().values('variation').annotate(cnt=Count('id'))
}
c_by_item = {
p['position__item']: p['cnt']
for p in cqs.order_by().values('position__item').annotate(cnt=Count('id'))
}
c_by_variation = {
p['position__variation']: p['cnt']
for p in cqs.order_by().values('position__variation').annotate(cnt=Count('id'))
}
if not clist.all_products:
items = clist.limit_products
else:
items = clist.event.items
response['items'] = []
for item in items.order_by('category__position', 'position', 'pk').prefetch_related('variations'):
i = {
'id': item.pk,
'name': str(item),
'admission': item.admission,
'checkin_count': c_by_item.get(item.pk, 0),
'position_count': op_by_item.get(item.pk, 0),
'variations': []
ev = clist.subevent or clist.event
response = {
'event': {
'name': str(ev.name),
},
'checkin_count': cqs.count(),
'position_count': pqs.count()
}
for var in item.variations.all():
i['variations'].append({
'id': var.pk,
'value': str(var),
'checkin_count': c_by_variation.get(var.pk, 0),
'position_count': op_by_variation.get(var.pk, 0),
})
response['items'].append(i)
return Response(response)
op_by_item = {
p['item']: p['cnt']
for p in pqs.order_by().values('item').annotate(cnt=Count('id'))
}
op_by_variation = {
p['variation']: p['cnt']
for p in pqs.order_by().values('variation').annotate(cnt=Count('id'))
}
c_by_item = {
p['position__item']: p['cnt']
for p in cqs.order_by().values('position__item').annotate(cnt=Count('id'))
}
c_by_variation = {
p['position__variation']: p['cnt']
for p in cqs.order_by().values('position__variation').annotate(cnt=Count('id'))
}
if not clist.all_products:
items = clist.limit_products
else:
items = clist.event.items
response['items'] = []
for item in items.order_by('category__position', 'position', 'pk').prefetch_related('variations'):
i = {
'id': item.pk,
'name': str(item),
'admission': item.admission,
'checkin_count': c_by_item.get(item.pk, 0),
'position_count': op_by_item.get(item.pk, 0),
'variations': []
}
for var in item.variations.all():
i['variations'].append({
'id': var.pk,
'value': str(var),
'checkin_count': c_by_variation.get(var.pk, 0),
'position_count': op_by_variation.get(var.pk, 0),
})
response['items'].append(i)
return Response(response)
with scopes_disabled():

View File

@@ -35,7 +35,7 @@ class DeviceSerializer(serializers.ModelSerializer):
model = Device
fields = [
'organizer', 'device_id', 'unique_serial', 'api_token',
'name'
'name', 'security_profile'
]

View File

@@ -15,7 +15,7 @@ from pretix.api.serializers.event import (
)
from pretix.api.views import ConditionalListView
from pretix.base.models import (
CartPosition, Device, Event, ItemCategory, TaxRule, TeamAPIToken,
CartPosition, Device, Event, TaxRule, TeamAPIToken,
)
from pretix.base.models.event import SubEvent
from pretix.helpers.dicts import merge_dicts
@@ -73,6 +73,7 @@ class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.none()
lookup_field = 'slug'
lookup_url_kwarg = 'event'
lookup_value_regex = '[^/]+'
permission_classes = (EventCRUDPermission,)
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
ordering = ('slug',)
@@ -228,7 +229,7 @@ with scopes_disabled():
class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
serializer_class = SubEventSerializer
queryset = ItemCategory.objects.none()
queryset = SubEvent.objects.none()
write_permission = 'can_change_event_settings'
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
filterset_class = SubEventFilter

View File

@@ -3,8 +3,9 @@ import logging
from django import forms
from django.conf import settings
from django.utils.translation import gettext as _
from oauth2_provider.exceptions import OAuthToolkitError
from oauth2_provider.exceptions import FatalClientError, OAuthToolkitError
from oauth2_provider.forms import AllowForm
from oauth2_provider.settings import oauth2_settings
from oauth2_provider.views import (
AuthorizationView as BaseAuthorizationView,
RevokeTokenView as BaseRevokeTokenView, TokenView as BaseTokenView,
@@ -24,9 +25,12 @@ class OAuthAllowForm(AllowForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
scope = kwargs.pop('scope')
super().__init__(*args, **kwargs)
self.fields['organizers'].queryset = Organizer.objects.filter(
pk__in=user.teams.values_list('organizer', flat=True))
if scope == 'profile':
del self.fields['organizers']
class AuthorizationView(BaseAuthorizationView):
@@ -36,6 +40,7 @@ class AuthorizationView(BaseAuthorizationView):
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
kwargs['scope'] = self.request.GET.get('scope')
return kwargs
def get_context_data(self, **kwargs):
@@ -43,8 +48,14 @@ class AuthorizationView(BaseAuthorizationView):
ctx['settings'] = settings
return ctx
def create_authorization_response(self, request, scopes, credentials, allow, organizers):
credentials["organizers"] = organizers
def validate_authorization_request(self, request):
require_approval = request.GET.get("approval_prompt", oauth2_settings.REQUEST_APPROVAL_PROMPT)
if require_approval != 'force' and request.GET.get('scope') != 'profile':
raise FatalClientError('Combnination of require_approval and scope values not allowed.')
return super().validate_authorization_request(request)
def create_authorization_response(self, request, scopes, credentials, allow, organizers=None):
credentials["organizers"] = organizers or []
return super().create_authorization_response(request, scopes, credentials, allow)
def form_valid(self, form):

View File

@@ -228,6 +228,7 @@ class OrderViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['POST'])
def mark_paid(self, request, **kwargs):
order = self.get_object()
send_mail = request.data.get('send_email', True)
if order.status in (Order.STATUS_PENDING, Order.STATUS_EXPIRED):
@@ -269,6 +270,7 @@ class OrderViewSet(viewsets.ModelViewSet):
try:
p.confirm(auth=self.request.auth,
user=self.request.user if request.user.is_authenticated else None,
send_mail=send_mail,
count_waitinglist=False)
except Quota.QuotaExceededException as e:
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
@@ -976,6 +978,7 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
def confirm(self, request, **kwargs):
payment = self.get_object()
force = request.data.get('force', False)
send_mail = request.data.get('send_email', True)
if payment.state not in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED):
return Response({'detail': 'Invalid state of payment'}, status=status.HTTP_400_BAD_REQUEST)
@@ -984,6 +987,7 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
payment.confirm(user=self.request.user if self.request.user.is_authenticated else None,
auth=self.request.auth,
count_waitinglist=False,
send_mail=send_mail,
force=force)
except Quota.QuotaExceededException as e:
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)

View File

@@ -6,20 +6,22 @@ from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import filters, serializers, status, viewsets
from rest_framework import filters, mixins, serializers, status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from pretix.api.models import OAuthAccessToken
from pretix.api.serializers.organizer import (
GiftCardSerializer, OrganizerSerializer, SeatingPlanSerializer,
TeamAPITokenSerializer, TeamInviteSerializer, TeamMemberSerializer,
TeamSerializer,
DeviceSerializer, GiftCardSerializer, OrganizerSerializer,
SeatingPlanSerializer, TeamAPITokenSerializer, TeamInviteSerializer,
TeamMemberSerializer, TeamSerializer,
)
from pretix.base.models import (
GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite, User,
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
User,
)
from pretix.helpers.dicts import merge_dicts
@@ -29,6 +31,7 @@ class OrganizerViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Organizer.objects.none()
lookup_field = 'slug'
lookup_url_kwarg = 'organizer'
lookup_value_regex = '[^/]+'
filter_backends = (filters.OrderingFilter,)
ordering = ('slug',)
ordering_fields = ('name', 'slug')
@@ -352,3 +355,44 @@ class TeamAPITokenViewSet(CreateModelMixin, DestroyModelMixin, viewsets.ReadOnly
serializer = self.get_serializer_class()(instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_200_OK, headers=headers)
class DeviceViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
GenericViewSet):
serializer_class = DeviceSerializer
queryset = Device.objects.none()
permission = 'can_change_organizer_settings'
write_permission = 'can_change_organizer_settings'
lookup_field = 'device_id'
def get_queryset(self):
return self.request.organizer.devices.order_by('pk')
def get_serializer_context(self):
ctx = super().get_serializer_context()
ctx['organizer'] = self.request.organizer
return ctx
@transaction.atomic()
def perform_create(self, serializer):
inst = serializer.save(organizer=self.request.organizer)
inst.log_action(
'pretix.device.created',
user=self.request.user,
auth=self.request.auth,
data=merge_dicts(self.request.data, {'id': inst.pk})
)
@transaction.atomic()
def perform_update(self, serializer):
inst = serializer.save()
inst.log_action(
'pretix.device.changed',
user=self.request.user,
auth=self.request.auth,
data=self.request.data
)
return inst

View File

@@ -3,14 +3,18 @@ from rest_framework.authentication import SessionAuthentication
from rest_framework.response import Response
from rest_framework.views import APIView
from pretix.api.auth.permission import ProfilePermission
class MeView(APIView):
authentication_classes = (SessionAuthentication, OAuth2Authentication)
permission_classes = (ProfilePermission,)
def get(self, request, format=None):
return Response({
'email': request.user.email,
'fullname': request.user.fullname,
'locale': request.user.locale,
'is_staff': request.user.is_staff,
'timezone': request.user.timezone
})

View File

@@ -85,6 +85,8 @@ class ParametrizedOrderWebhookEvent(WebhookEvent):
def build_payload(self, logentry: LogEntry):
order = logentry.content_object
if not order:
return None
return {
'notification_id': logentry.pk,
@@ -99,6 +101,8 @@ class ParametrizedOrderPositionWebhookEvent(ParametrizedOrderWebhookEvent):
def build_payload(self, logentry: LogEntry):
d = super().build_payload(logentry)
if d is None:
return None
d['orderposition_id'] = logentry.parsed_data.get('position')
d['orderposition_positionid'] = logentry.parsed_data.get('positionid')
d['checkin_list'] = logentry.parsed_data.get('list')
@@ -218,6 +222,10 @@ def send_webhook(self, logentry_id: int, action_type: str, webhook_id: int):
return # Ignore, e.g. plugin not installed
payload = event_type.build_payload(logentry)
if payload is None:
# Content object deleted?
return
t = time.time()
try:

View File

@@ -98,7 +98,10 @@ class BaseAuthBackend:
class NativeAuthBackend(BaseAuthBackend):
identifier = 'native'
verbose_name = _('pretix User')
@property
def verbose_name(self):
return _('{system} User').format(system=settings.PRETIX_INSTANCE_NAME)
@property
def login_form_fields(self) -> dict:

View File

@@ -114,7 +114,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
'site_url': settings.SITE_URL,
'body': body_md,
'subject': str(subject),
'color': '#8E44B3',
'color': settings.PRETIX_PRIMARY_COLOR,
'rtl': get_language() in settings.LANGUAGES_RTL
}
if self.event:
@@ -222,6 +222,7 @@ class SimpleFunctionalMailTextPlaceholder(BaseMailTextPlaceholder):
def get_available_placeholders(event, base_parameters):
if 'order' in base_parameters:
base_parameters.append('invoice_address')
base_parameters.append('position_or_address')
params = {}
for r, val in register_mail_placeholders.send(sender=event):
if not isinstance(val, (list, tuple)):
@@ -240,7 +241,9 @@ def get_email_context(**kwargs):
try:
kwargs['invoice_address'] = kwargs['order'].invoice_address
except InvoiceAddress.DoesNotExist:
kwargs['invoice_address'] = InvoiceAddress()
kwargs['invoice_address'] = InvoiceAddress(order=kwargs['order'])
finally:
kwargs.setdefault("position_or_address", kwargs['invoice_address'])
ctx = {}
for r, val in register_mail_placeholders.send(sender=event):
if not isinstance(val, (list, tuple)):
@@ -268,7 +271,8 @@ def get_best_name(position_or_address, parts=False):
if isinstance(position_or_address, InvoiceAddress):
if position_or_address.name:
return position_or_address.name_parts if parts else position_or_address.name
position_or_address = position_or_address.order.positions.exclude(attendee_name_cached="").exclude(attendee_name_cached__isnull=True).first()
elif position_or_address.order:
position_or_address = position_or_address.order.positions.exclude(attendee_name_cached="").exclude(attendee_name_cached__isnull=True).first()
if isinstance(position_or_address, OrderPosition):
if position_or_address.attendee_name:

View File

@@ -388,6 +388,11 @@ class OrderListExporter(MultiSheetListExporter):
pgettext('address', 'State'),
_('Voucher'),
_('Pseudonymization ID'),
_('Seat ID'),
_('Seat name'),
_('Seat zone'),
_('Seat row'),
_('Seat number'),
]
questions = list(Question.objects.filter(event__in=self.events))
@@ -471,6 +476,18 @@ class OrderListExporter(MultiSheetListExporter):
op.voucher.code if op.voucher else '',
op.pseudonymization_id,
]
if op.seat:
row += [
op.seat.seat_guid,
str(op.seat),
op.seat.zone_name,
op.seat.row_name,
op.seat.seat_number,
]
else:
row += ['', '', '', '', '']
acache = {}
for a in op.answers.all():
# We do not want to localize Date, Time and Datetime question answers, as those can lead
@@ -645,11 +662,13 @@ class GiftcardRedemptionListExporter(ListExporter):
def iterate_list(self, form_data):
payments = OrderPayment.objects.filter(
order__event__in=self.events,
provider='giftcard'
provider='giftcard',
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED),
).order_by('created')
refunds = OrderRefund.objects.filter(
order__event__in=self.events,
provider='giftcard'
provider='giftcard',
state=OrderRefund.REFUND_STATE_DONE
).order_by('created')
objs = sorted(list(payments) + list(refunds), key=lambda o: (o.order.code, o.created))

View File

@@ -36,8 +36,8 @@ from pretix.base.i18n import language
from pretix.base.models import InvoiceAddress, Question, QuestionOption
from pretix.base.models.tax import EU_COUNTRIES, cc_to_vat_prefix
from pretix.base.settings import (
COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SCHEMES,
PERSON_NAME_TITLE_GROUPS,
COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SALUTATIONS,
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS,
)
from pretix.base.templatetags.rich_text import rich_text
from pretix.control.forms import ExtFileField, SplitDateTimeField
@@ -49,7 +49,7 @@ from pretix.presale.signals import question_form_fields
logger = logging.getLogger(__name__)
REQUIRED_NAME_PARTS = ['given_name', 'family_name', 'full_name']
REQUIRED_NAME_PARTS = ['salutation', 'given_name', 'family_name', 'full_name']
class NamePartsWidget(forms.MultiWidget):
@@ -73,6 +73,8 @@ class NamePartsWidget(forms.MultiWidget):
a['data-fname'] = fname
if fname == 'title' and self.titles:
widgets.append(Select(attrs=a, choices=[('', '')] + [(d, d) for d in self.titles[1]]))
elif fname == 'salutation':
widgets.append(Select(attrs=a, choices=[('', '---')] + [(s, s) for s in PERSON_NAME_SALUTATIONS]))
else:
widgets.append(self.widget(attrs=a))
super().__init__(widgets, attrs)
@@ -162,12 +164,18 @@ class NamePartsFormField(forms.MultiValueField):
**d,
choices=[('', '')] + [(d, d) for d in self.scheme_titles[1]]
)
field.part_name = fname
fields.append(field)
elif fname == 'salutation':
d = dict(defaults)
d.pop('max_length', None)
field = forms.ChoiceField(
**d,
choices=[('', '---')] + [(s, s) for s in PERSON_NAME_SALUTATIONS]
)
else:
field = forms.CharField(**defaults)
field.part_name = fname
fields.append(field)
field.part_name = fname
fields.append(field)
super().__init__(
fields=fields, require_all_fields=False, *args, **kwargs
)

View File

@@ -396,13 +396,13 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
p_str = (
shorten(self.invoice.event.name) + '\n' +
pgettext('invoice', '{from_date}\nuntil {to_date}').format(
from_date=self.invoice.event.get_date_from_display(),
to_date=self.invoice.event.get_date_to_display()
from_date=self.invoice.event.get_date_from_display(show_times=False),
to_date=self.invoice.event.get_date_to_display(show_times=False)
)
)
else:
p_str = (
shorten(self.invoice.event.name) + '\n' + self.invoice.event.get_date_from_display()
shorten(self.invoice.event.name) + '\n' + self.invoice.event.get_date_from_display(show_times=False)
)
else:
p_str = shorten(self.invoice.event.name)

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.0.9 on 2020-10-13 08:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0162_remove_seat_name'),
]
operations = [
migrations.AddField(
model_name='device',
name='security_profile',
field=models.CharField(default='full', max_length=190, null=True),
),
]

View File

@@ -6,6 +6,7 @@ from django.utils.crypto import get_random_string
from django.utils.translation import gettext_lazy as _
from django_scopes import ScopedManager, scopes_disabled
from pretix.api.auth.devicesecurity import DEVICE_SECURITY_PROFILES
from pretix.base.models import LoggedModel
@@ -74,6 +75,13 @@ class Device(LoggedModel):
max_length=190,
null=True, blank=True
)
security_profile = models.CharField(
max_length=190,
choices=[(k, v.verbose_name) for k, v in DEVICE_SECURITY_PROFILES.items()],
default='full',
null=True,
blank=False
)
objects = ScopedManager(organizer='organizer')

View File

@@ -12,7 +12,7 @@ from django.core.files.storage import default_storage
from django.core.mail import get_connection
from django.core.validators import RegexValidator
from django.db import models
from django.db.models import Exists, OuterRef, Prefetch, Q, Subquery
from django.db.models import Exists, OuterRef, Prefetch, Q, Subquery, Value
from django.template.defaultfilters import date as _date
from django.utils.crypto import get_random_string
from django.utils.formats import date_format
@@ -89,7 +89,7 @@ class EventMixin:
self.date_from.astimezone(tz), "TIME_FORMAT"
)
def get_date_to_display(self, tz=None, short=False) -> str:
def get_date_to_display(self, tz=None, show_times=True, short=False) -> str:
"""
Returns a formatted string containing the start date of the event with respect
to the current locale and to the ``show_times`` setting. Returns an empty string
@@ -100,14 +100,14 @@ class EventMixin:
return ""
return _date(
self.date_to.astimezone(tz),
("SHORT_" if short else "") + ("DATETIME_FORMAT" if self.settings.show_times else "DATE_FORMAT")
("SHORT_" if short else "") + ("DATETIME_FORMAT" if self.settings.show_times and show_times else "DATE_FORMAT")
)
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.
of the event with respect to the current locale and to the ``show_date_to``
setting. Times are not shown.
"""
tz = tz or self.timezone
if (not self.settings.show_date_to and not force_show_end) or not self.date_to:
@@ -189,7 +189,9 @@ class EventMixin:
).order_by().values_list('quotas__pk').annotate(
items=GroupConcat('pk', delimiter=',')
).values('items')
return qs.prefetch_related(
return qs.annotate(
has_paid_item=Exists(Item.objects.filter(event_id=OuterRef(cls._event_id), default_price__gt=0))
).prefetch_related(
Prefetch(
'quotas',
to_attr='active_quotas',
@@ -280,6 +282,7 @@ class Event(EventMixin, LoggedModel):
"""
settings_namespace = 'event'
_event_id = 'pk'
CURRENCY_CHOICES = [(c.alpha_3, c.alpha_3 + " - " + c.name) for c in settings.CURRENCIES]
organizer = models.ForeignKey(Organizer, related_name="events", on_delete=models.PROTECT)
testmode = models.BooleanField(default=False)
@@ -786,7 +789,12 @@ class Event(EventMixin, LoggedModel):
'name_ascending': ('name', 'date_from'),
'name_descending': ('-name', 'date_from'),
}[ordering]
subevs = queryset.filter(
subevs = queryset.annotate(
has_paid_item=Value(
self.cache.get_or_set('has_paid_item', lambda: self.items.filter(default_price__gt=0).exists(), 3600),
output_field=models.BooleanField()
)
).filter(
Q(active=True) & Q(is_public=True) & (
Q(Q(date_to__isnull=True) & Q(date_from__gte=now() - timedelta(hours=24)))
| Q(date_to__gte=now() - timedelta(hours=24))
@@ -980,6 +988,7 @@ class SubEvent(EventMixin, LoggedModel):
:type location: str
"""
_event_id = 'event_id'
event = models.ForeignKey(Event, related_name="subevents", on_delete=models.PROTECT)
active = models.BooleanField(default=False, verbose_name=_("Active"),
help_text=_("Only with this checkbox enabled, this date is visible in the "

View File

@@ -1140,6 +1140,8 @@ class Question(LoggedModel):
return None
if self.type == Question.TYPE_CHOICE:
if isinstance(answer, QuestionOption):
return answer
q = Q(identifier=answer)
if isinstance(answer, int) or answer.isdigit():
q |= Q(pk=answer)
@@ -1154,6 +1156,8 @@ class Question(LoggedModel):
Q(identifier__in=answer.split(","))
))
llen = len(answer.split(','))
elif all(isinstance(o, QuestionOption) for o in answer):
return o
else:
l_ = list(self.options.filter(
Q(pk__in=[a for a in answer if isinstance(a, int) or a.isdigit()]) |

View File

@@ -174,7 +174,7 @@ class TaxRule(LoggedModel):
return Decimal(self.rate)
def tax(self, base_price, base_price_is='auto', currency=None, override_tax_rate=None, invoice_address=None,
subtract_from_gross=Decimal('0.00')):
subtract_from_gross=Decimal('0.00'), gross_price_is_tax_rate: Decimal = None):
from .event import Event
try:
currency = currency or self.event.currency
@@ -186,7 +186,9 @@ class TaxRule(LoggedModel):
rate = override_tax_rate
elif invoice_address:
adjust_rate = self.tax_rate_for(invoice_address)
if adjust_rate != rate:
if adjust_rate == gross_price_is_tax_rate and base_price_is == 'gross':
rate = adjust_rate
elif adjust_rate != rate:
normal_price = self.tax(base_price, base_price_is, currency, subtract_from_gross=subtract_from_gross)
base_price = normal_price.net
base_price_is = 'net'

View File

@@ -1,4 +1,5 @@
import re
from collections import defaultdict
from decimal import Decimal, DecimalException
import pycountry
@@ -12,11 +13,13 @@ from django.utils.translation import (
)
from django_countries import countries
from django_countries.fields import Country
from i18nfield.strings import LazyI18nString
from pretix.base.channels import get_all_sales_channels
from pretix.base.forms.questions import guess_country
from pretix.base.models import (
ItemVariation, OrderPosition, QuestionAnswer, QuestionOption, Seat,
ItemVariation, OrderPosition, Question, QuestionAnswer, QuestionOption,
Seat,
)
from pretix.base.services.pricing import get_price
from pretix.base.settings import (
@@ -417,7 +420,7 @@ class AttendeeStreet(ImportColumn):
return _('Attendee address') + ': ' + _('Address')
def assign(self, value, order, position, invoice_address, **kwargs):
position.address = value or ''
position.street = value or ''
class AttendeeZip(ImportColumn):
@@ -528,7 +531,7 @@ class Secret(ImportColumn):
super().__init__(*args)
def clean(self, value, previous_values):
if value and (value in self._cached or OrderPosition.all.filter(order__event=self.event, secret=value).exists()):
if value and (value in self._cached or OrderPosition.all.filter(order__event__organizer=self.event.organizer, secret=value).exists()):
raise ValidationError(
_('You cannot assign a position secret that already exists.')
)
@@ -626,6 +629,22 @@ class Comment(ImportColumn):
class QuestionColumn(ImportColumn):
def __init__(self, event, q):
self.q = q
self.option_resolve_cache = defaultdict(set)
for opt in q.options.all():
self.option_resolve_cache[str(opt.id)].add(opt)
self.option_resolve_cache[opt.identifier].add(opt)
if isinstance(opt.answer, LazyI18nString):
if isinstance(opt.answer.data, dict):
for v in opt.answer.data.values():
self.option_resolve_cache[v.strip()].add(opt)
else:
self.option_resolve_cache[opt.answer.strip()].add(opt)
else:
self.option_resolve_cache[opt.answer.strip()].add(opt)
super().__init__(event)
@property
@@ -638,7 +657,23 @@ class QuestionColumn(ImportColumn):
def clean(self, value, previous_values):
if value:
return self.q.clean_answer(value)
if self.q.type == Question.TYPE_CHOICE:
if value not in self.option_resolve_cache:
raise ValidationError(_('Invalid option selected.'))
if len(self.option_resolve_cache[value]) > 1:
raise ValidationError(_('Ambigous option selected.'))
return list(self.option_resolve_cache[value])[0]
elif self.q.type == Question.TYPE_CHOICE_MULTIPLE:
values = value.split(',')
if any(v.strip() not in self.option_resolve_cache for v in values):
raise ValidationError(_('Invalid option selected.'))
if any(len(self.option_resolve_cache[v.strip()]) > 1 for v in values):
raise ValidationError(_('Ambigous option selected.'))
return [list(self.option_resolve_cache[v.strip()])[0] for v in values]
else:
return self.q.clean_answer(value)
def assign(self, value, order, position, invoice_address, **kwargs):
if value:
@@ -702,7 +737,7 @@ def get_all_columns(event):
SeatColumn(event),
Comment(event)
]
for q in event.questions.exclude(type='F'):
for q in event.questions.prefetch_related('options').exclude(type=Question.TYPE_FILE):
default.append(QuestionColumn(event, q))
for recv, resp in order_import_columns.send(sender=event):

View File

@@ -1134,7 +1134,7 @@ class GiftCardPayment(BasePaymentProvider):
cart['raw']
)
total += sum([f.value for f in fees])
remainder = total - gc.value
remainder = total
if remainder > Decimal('0.00'):
del cs['payment']
messages.success(request, _("Your gift card has been applied, but {} still need to be paid. Please select a payment method.").format(

View File

@@ -66,6 +66,7 @@ error_messages = {
"%(min)s items of it."),
'not_started': _('The presale period for this event has not yet started.'),
'ended': _('The presale period for this event has ended.'),
'payment_ended': _('All payments for this event need to be confirmed already, so no new orders can be created.'),
'some_subevent_not_started': _('The presale period for this event has not yet started. The affected positions '
'have been removed from your cart.'),
'some_subevent_ended': _('The presale period for one of the events in your cart has ended. The affected '
@@ -169,7 +170,7 @@ class CartManager:
time(hour=23, minute=59, second=59)
), self.event.timezone)
if term_last < self.now_dt:
raise CartError(error_messages['ended'])
raise CartError(error_messages['payment_ended'])
def _extend_expiry_of_valid_existing_positions(self):
# Extend this user's cart session to ensure all items in the cart expire at the same time
@@ -304,7 +305,7 @@ class CartManager:
time(hour=23, minute=59, second=59)
), self.event.timezone)
if term_last < self.now_dt:
raise CartError(error_messages['ended'])
raise CartError(error_messages['payment_ended'])
if isinstance(op, self.AddOperation):
if op.item.category and op.item.category.is_addon and not (op.addon_to and op.addon_to != 'FAKE'):
@@ -1085,16 +1086,14 @@ def get_fees(event, request, total, invoice_address, provider, positions):
if cs.get('gift_cards'):
gcs = cs['gift_cards']
gc_qs = event.organizer.accepted_gift_cards.filter(pk__in=cs.get('gift_cards'), currency=event.currency)
summed = 0
for gc in gc_qs:
if gc.testmode != event.testmode:
gcs.remove(gc.pk)
continue
fval = Decimal(gc.value) # TODO: don't require an extra query
fval = min(fval, total - summed)
fval = min(fval, total)
if fval > 0:
total -= fval
summed += fval
fees.append(OrderFee(
fee_type=OrderFee.FEE_TYPE_GIFTCARD,
internal_type='giftcard',

View File

@@ -7,7 +7,7 @@ import ssl
import warnings
from email.mime.image import MIMEImage
from email.utils import formataddr
from typing import Any, Dict, List, Union
from typing import Any, Dict, List, Sequence, Union
from urllib.parse import urljoin, urlparse
import cssutils
@@ -27,7 +27,7 @@ from i18nfield.strings import LazyI18nString
from pretix.base.email import ClassicMailRenderer
from pretix.base.i18n import language
from pretix.base.models import (
Event, Invoice, InvoiceAddress, Order, OrderPosition, User,
CachedFile, Event, Invoice, InvoiceAddress, Order, OrderPosition, User,
)
from pretix.base.services.invoices import invoice_pdf_task
from pretix.base.services.tasks import TransactionAwareTask
@@ -52,10 +52,11 @@ class SendMailException(Exception):
pass
def mail(email: str, subject: str, template: Union[str, LazyI18nString],
context: Dict[str, Any]=None, event: Event=None, locale: str=None,
order: Order=None, position: OrderPosition=None, headers: dict=None, sender: str=None,
invoices: list=None, attach_tickets=False, auto_email=True, user=None, attach_ical=False):
def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, LazyI18nString],
context: Dict[str, Any] = None, event: Event = None, locale: str = None,
order: Order = None, position: OrderPosition = None, headers: dict = None, sender: str = None,
invoices: Sequence = None, attach_tickets=False, auto_email=True, user=None, attach_ical=False,
attach_cached_files: Sequence = None):
"""
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
@@ -96,6 +97,8 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
:param user: The user this email is sent to
:param attach_cached_files: A list of cached file to attach to this email.
:raises MailOrderException: on obvious, immediate failures. Not raising an exception does not necessarily mean
that the email has been sent, just that it has been queued by the email backend.
"""
@@ -214,7 +217,7 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
body_html = None
send_task = mail_send_task.si(
to=[email],
to=[email] if isinstance(email, str) else list(email),
bcc=bcc,
subject=subject,
body=body_plain,
@@ -227,7 +230,8 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
position=position.pk if position else None,
attach_tickets=attach_tickets,
attach_ical=attach_ical,
user=user.pk if user else None
user=user.pk if user else None,
attach_cached_files=[cf.id for cf in attach_cached_files] if attach_cached_files else [],
)
if invoices:
@@ -255,9 +259,9 @@ class CustomEmail(EmailMultiAlternatives):
@app.task(base=TransactionAwareTask, bind=True, acks_late=True)
def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: str, sender: str,
event: int=None, position: int=None, headers: dict=None, bcc: List[str]=None,
invoices: List[int]=None, order: int=None, attach_tickets=False, user=None,
attach_ical=False) -> bool:
event: int = None, position: int = None, headers: dict = None, bcc: List[str] = None,
invoices: List[int] = None, order: int = None, attach_tickets=False, user=None,
attach_ical=False, attach_cached_files: List[int] = None) -> bool:
email = CustomEmail(subject, body, sender, to=to, bcc=bcc, headers=headers)
if html is not None:
html_message = SafeMIMEMultipart(_subtype='related', encoding=settings.DEFAULT_CHARSET)
@@ -349,6 +353,19 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
logger.exception('Could not attach invoice to email')
pass
if attach_cached_files:
for cf in CachedFile.objects.filter(id__in=attach_cached_files):
if cf.file:
try:
email.attach(
cf.filename,
cf.file.file.read(),
cf.type,
)
except:
logger.exception('Could not attach file to email')
pass
email = global_email_filter.send_chained(event, 'message', message=email, user=user, order=order)
try:

View File

@@ -91,7 +91,7 @@ def send_notification_mail(notification: Notification, user: User):
ctx = {
'site': settings.PRETIX_INSTANCE_NAME,
'site_url': settings.SITE_URL,
'color': '#8E44B3',
'color': settings.PRETIX_PRIMARY_COLOR,
'notification': notification,
'settings_url': build_absolute_uri(
'control:user.settings.notifications',

View File

@@ -103,7 +103,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
order._address.name_parts = {'_scheme': event.settings.name_scheme}
orders.append(order)
position = OrderPosition()
position = OrderPosition(positionid=len(order._positions) + 1)
position.attendee_name_parts = {'_scheme': event.settings.name_scheme}
position.meta_info = {}
order._positions.append(position)

View File

@@ -618,8 +618,10 @@ def _check_positions(event: Event, now_dt: datetime, positions: List[CartPositio
except ItemBundle.MultipleObjectsReturned:
raise OrderError("Invalid product configuration (duplicate bundle)")
price = get_price(cp.item, cp.variation, cp.voucher, bprice, cp.subevent, custom_price_is_net=False,
custom_price_is_tax_rate=cp.override_tax_rate,
invoice_address=address, force_custom_price=True, max_discount=max_discount)
pbv = get_price(cp.item, cp.variation, None, bprice, cp.subevent, custom_price_is_net=False,
custom_price_is_tax_rate=cp.override_tax_rate,
invoice_address=address, force_custom_price=True, max_discount=max_discount)
changed_prices[cp.pk] = bprice
else:
@@ -631,10 +633,10 @@ def _check_positions(event: Event, now_dt: datetime, positions: List[CartPositio
price = get_price(cp.item, cp.variation, cp.voucher, cp.price, cp.subevent, custom_price_is_net=False,
addon_to=cp.addon_to, invoice_address=address, bundled_sum=bundled_sum,
max_discount=max_discount)
max_discount=max_discount, custom_price_is_tax_rate=cp.override_tax_rate)
pbv = get_price(cp.item, cp.variation, None, cp.price, cp.subevent, custom_price_is_net=False,
addon_to=cp.addon_to, invoice_address=address, bundled_sum=bundled_sum,
max_discount=max_discount)
max_discount=max_discount, custom_price_is_tax_rate=cp.override_tax_rate)
if max_discount is not None:
v_budget[cp.voucher] = v_budget[cp.voucher] + current_discount - (pbv.gross - price.gross)
@@ -1051,7 +1053,7 @@ def send_download_reminders(sender, **kwargs):
download_reminder_sent=False,
datetime__lte=now() - timedelta(hours=2),
first_date__gte=today,
).only('pk', 'event_id').order_by('event_id')
).only('pk', 'event_id', 'sales_channel').order_by('event_id')
event_id = None
days = None
event = None
@@ -1882,7 +1884,7 @@ class OrderChangeManager:
def _reissue_invoice(self):
i = self.order.invoices.filter(is_cancellation=False).last()
if self.reissue_invoice and self._invoice_dirty:
if i:
if i and not i.refered.exists():
self._invoices.append(generate_cancellation(i))
if invoice_qualified(self.order) and \
(i or
@@ -2205,8 +2207,11 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay
@receiver(order_paid, dispatch_uid="pretixbase_order_paid_giftcards")
@receiver(order_changed, dispatch_uid="pretixbase_order_changed_giftcards")
@transaction.atomic()
def signal_listener_issue_giftcards(sender: Event, order: Order, **kwargs):
if order.status != Order.STATUS_PAID:
return
any_giftcards = False
for p in order.positions.all():
if p.item.issue_giftcard:

View File

@@ -11,6 +11,7 @@ from pretix.base.models.tax import TAXED_ZERO, TaxedPrice, TaxRule
def get_price(item: Item, variation: ItemVariation = None,
voucher: Voucher = None, custom_price: Decimal = None,
subevent: SubEvent = None, custom_price_is_net: bool = False,
custom_price_is_tax_rate: Decimal=None,
addon_to: AbstractPosition = None, invoice_address: InvoiceAddress = None,
force_custom_price: bool = False, bundled_sum: Decimal = Decimal('0.00'),
max_discount: Decimal = None, tax_rule=None) -> TaxedPrice:
@@ -66,7 +67,7 @@ def get_price(item: Item, variation: ItemVariation = None,
price = tax_rule.tax(max(custom_price, price.net), base_price_is='net',
invoice_address=invoice_address, subtract_from_gross=bundled_sum)
else:
price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross',
price = tax_rule.tax(max(custom_price, price.gross), base_price_is='gross', gross_price_is_tax_rate=custom_price_is_tax_rate,
invoice_address=invoice_address, subtract_from_gross=bundled_sum)
else:
price = tax_rule.tax(price, invoice_address=invoice_address, subtract_from_gross=bundled_sum)

View File

@@ -54,7 +54,7 @@ def export(event: Event, shredders: List[str]) -> None:
cf = CachedFile()
cf.date = now()
cf.filename = event.slug + '.zip'
cf.type = 'application/pdf'
cf.type = 'application/zip'
cf.expires = now() + timedelta(hours=1)
cf.save()
cf.file.save(cachedfile_name(cf, cf.filename), rawfile)

View File

@@ -668,8 +668,8 @@ DEFAULTS = {
'type': str,
'form_class': forms.ChoiceField,
'serializer_class': serializers.ChoiceField,
'serializer_kwargs': country_choice_kwargs,
'form_kwargs': country_choice_kwargs,
'serializer_kwargs': lambda: dict(**country_choice_kwargs()),
'form_kwargs': lambda: dict(label=_('Country'), **country_choice_kwargs()),
},
'invoice_address_from_tax_id': {
'default': '',
@@ -1580,7 +1580,7 @@ Your {event} team"""))
'type': bool
},
'primary_color': {
'default': '#8E44B3',
'default': settings.PRETIX_PRIMARY_COLOR,
'type': str,
},
'theme_color_success': {
@@ -1825,6 +1825,15 @@ Your {event} team"""))
'seating_distance_within_row': {
'default': 'False',
'type': bool
},
'checkout_show_copy_answers_button': {
'default': 'True',
'type': bool,
'form_class': forms.BooleanField,
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Show button to copy user input from other products"),
),
}
}
PERSON_NAME_TITLE_GROUPS = OrderedDict([
@@ -1836,7 +1845,7 @@ PERSON_NAME_TITLE_GROUPS = OrderedDict([
'Mx',
'Dr',
'Professor',
'Sir'
'Sir',
))),
('german_common', (_('Most common German titles'), (
'Dr.',
@@ -1844,9 +1853,16 @@ PERSON_NAME_TITLE_GROUPS = OrderedDict([
'Prof. Dr.',
)))
])
PERSON_NAME_SALUTATIONS = [
pgettext_lazy("person_name_salutation", "Ms"),
pgettext_lazy("person_name_salutation", "Mr"),
]
PERSON_NAME_SCHEMES = OrderedDict([
('given_family', {
'fields': (
# field_name, label, weight for widget width
('given_name', _('Given name'), 1),
('family_name', _('Family name'), 1),
),
@@ -2001,6 +2017,24 @@ PERSON_NAME_SCHEMES = OrderedDict([
'_scheme': 'full_transcription',
},
}),
('salutation_title_given_family', {
'fields': (
('salutation', pgettext_lazy('person_name', 'Salutation'), 1),
('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(key, '') for key in ["title", "given_name", "family_name"]) if p
),
'sample': {
'salutation': pgettext_lazy('person_name_sample', 'Mr'),
'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_salutation_given_family',
},
}),
])
COUNTRIES_WITH_STATE_IN_ADDRESS = {
# Source: http://www.bitboost.com/ref/international-address-formats.html
@@ -2016,7 +2050,6 @@ COUNTRIES_WITH_STATE_IN_ADDRESS = {
'US': (['State', 'Outlying area', 'District'], 'short'),
}
settings_hierarkey = Hierarkey(attribute_name='settings')
for k, v in DEFAULTS.items():
@@ -2086,7 +2119,7 @@ class SettingsSandbox:
def __delattr__(self, key: str) -> None:
del self._event.settings[self._convert_key(key)]
def get(self, key: str, default: Any=None, as_type: type=str):
def get(self, key: str, default: Any = None, as_type: type = str):
return self._event.settings.get(self._convert_key(key), default=default, as_type=as_type)
def set(self, key: str, value: Any):

View File

@@ -53,7 +53,15 @@ class BaseQuestionsViewMixin:
data=(self.request.POST if self.request.method == 'POST' else None),
files=(self.request.FILES if self.request.method == 'POST' else None))
form.pos = cartpos or orderpos
form.show_copy_answers_to_addon_button = form.pos.addon_to and set(form.pos.addon_to.item.questions.all()) & set(form.pos.item.questions.all())
form.show_copy_answers_to_addon_button = form.pos.addon_to and (
set(form.pos.addon_to.item.questions.all()) & set(form.pos.item.questions.all()) or
(form.pos.addon_to.item.admission and form.pos.item.admission and (
self.request.event.settings.attendee_names_asked or
self.request.event.settings.attendee_emails_asked or
self.request.event.settings.attendee_company_asked or
self.request.event.settings.attendee_addresses_asked
))
)
if len(form.fields) > 0:
formlist.append(form)
return formlist

View File

@@ -83,6 +83,7 @@ class SimpleCheckinListForm(forms.ModelForm):
'all_products',
'limit_products',
'include_pending',
'allow_entry_after_exit',
]
widgets = {
'limit_products': forms.CheckboxSelectMultiple(attrs={

View File

@@ -522,6 +522,7 @@ class EventSettingsForm(SettingsForm):
'banner_text_bottom',
'order_email_asked_twice',
'last_order_modification_date',
'checkout_show_copy_answers_button',
]
def clean(self):

View File

@@ -287,11 +287,11 @@ class EventOrderFilterForm(OrderFilterForm):
for i in self.event.items.prefetch_related('variations').all():
variations = list(i.variations.all())
if variations:
choices.append((str(i.pk), _('{product} Any variation').format(product=i.name)))
choices.append((str(i.pk), _('{product} Any variation').format(product=str(i))))
for v in variations:
choices.append(('%d-%d' % (i.pk, v.pk), '%s %s' % (i.name, v.value)))
choices.append(('%d-%d' % (i.pk, v.pk), '%s %s' % (str(i), v.value)))
else:
choices.append((str(i.pk), i.name))
choices.append((str(i.pk), str(i)))
self.fields['item'].choices = choices
def filter_qs(self, qs):
@@ -827,6 +827,8 @@ class CheckInFilterForm(FilterForm):
'-item': ('-item__name', '-variation__value', '-order__code'),
'seat': ('seat__sorting_rank', 'seat__guid'),
'-seat': ('-seat__sorting_rank', '-seat__guid'),
'date': ('subevent__date_from', 'order__code'),
'-date': ('-subevent__date_from', '-order__code'),
'name': {'_order': F('display_name').asc(nulls_first=True),
'display_name': Coalesce('attendee_name_cached', 'addon_to__attendee_name_cached')},
'-name': {'_order': F('display_name').desc(nulls_last=True),

View File

@@ -193,7 +193,7 @@ class DeviceForm(forms.ModelForm):
class Meta:
model = Device
fields = ['name', 'all_events', 'limit_events']
fields = ['name', 'all_events', 'limit_events', 'security_profile']
widgets = {
'limit_events': forms.CheckboxSelectMultiple(attrs={
'data-inverse-dependency': '#id_all_events',

View File

@@ -19,6 +19,12 @@ def render_label(content, label_for=None, label_class=None, label_title='', opti
attrs['class'] = label_class
if label_title:
attrs['title'] = label_title
if text_value(content) == '&#160;':
# Empty label, e.g. checkbox
attrs.setdefault('class', '')
attrs['class'] += ' label-empty'
builder = '<{tag}{attrs}>{content}{opt}</{tag}>'
return format_html(
builder,

View File

@@ -2,7 +2,6 @@ from datetime import timedelta
from urllib.parse import urlencode
from django import forms
from django.core.exceptions import ValidationError
from django.forms import formset_factory
from django.urls import reverse
from django.utils.dates import MONTHS, WEEKDAYS
@@ -382,12 +381,6 @@ class TimeForm(forms.Form):
required=False
)
def clean(self):
d = super().clean()
if d.get('time_from') and d.get('time_to') and d['time_from'] > d['time_to']:
raise ValidationError({'time_to': _('The end of the event has to be later than its start.')})
return d
TimeFormSet = formset_factory(
TimeForm,

View File

@@ -128,7 +128,7 @@ class VoucherForm(I18nModelForm):
def clean(self):
data = super().clean()
if not self._errors and self.data.get('itemvar'):
if not self._errors:
try:
itemid = quotaid = None
iv = self.data.get('itemvar', '')
@@ -136,8 +136,10 @@ class VoucherForm(I18nModelForm):
quotaid = iv[2:]
elif '-' in iv:
itemid, varid = iv.split('-')
else:
elif iv:
itemid, varid = iv, None
else:
itemid, varid = None, None
if itemid:
self.instance.item = self.instance.event.items.get(pk=itemid)
@@ -146,11 +148,15 @@ class VoucherForm(I18nModelForm):
else:
self.instance.variation = None
self.instance.quota = None
else:
elif quotaid:
self.instance.quota = self.instance.event.quotas.get(pk=quotaid)
self.instance.item = None
self.instance.variation = None
else:
self.instance.quota = None
self.instance.item = None
self.instance.variation = None
except ObjectDoesNotExist:
raise ValidationError(_("Invalid product selected."))

View File

@@ -26,8 +26,10 @@
<li>{{ scope }}</li>
{% endfor %}
</ul>
<p>{% trans "Please select the organizer accounts this application should get access to:" %}</p>
{% bootstrap_field form.organizers layout="inline" %}
{% if form.organizers %}
<p>{% trans "Please select the organizer accounts this application should get access to:" %}</p>
{% bootstrap_field form.organizers layout="inline" %}
{% endif %}
{% bootstrap_form_errors form layout="control" %}
<p class="text-danger">

View File

@@ -10,6 +10,23 @@
<dd>Stripe Terminal</dd>
<dt>{% trans "ID" %}</dt>
<dd>{{ payment_info.payment_data.payment_intent }}</dd>
{% elif payment_info.payment_type == "terminal_zvt" %}
<dt>{% trans "Payment provider" %}</dt>
<dd>{% trans "ZVT Terminal" %}</dd>
<dt>{% trans "Trace number" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.traceNumber }}</dd>
<dt>{% trans "Payment type" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.paymentType }}</dd>
<dt>{% trans "Additional text" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.additionalText }}</dd>
<dt>{% trans "Turnover number" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.turnoverNumber }}</dd>
<dt>{% trans "Receipt number" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.receiptNumber }}</dd>
<dt>{% trans "Card type" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.cardName }}</dd>
<dt>{% trans "Card expiration" context "terminal_zvt" %}</dt>
<dd>{{ payment_info.payment_data.expiry }}</dd>
{% elif payment_info.payment_type == "sumup" %}
<dt>{% trans "Payment provider" %}</dt>
<dd>SumUp</dd>

View File

@@ -66,6 +66,10 @@
<a href="?{% url_replace request 'ordering' 'code'%}"><i class="fa fa-caret-up"></i></a></th>
<th>{% trans "Item" %} <a href="?{% url_replace request 'ordering' '-item'%}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'item'%}"><i class="fa fa-caret-up"></i></a></th>
{% if request.event.has_subevents and not checkinlist.subevent %}
<th>{% trans "Date" context "subevents" %} <a href="?{% url_replace request 'ordering' '-date'%}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'date'%}"><i class="fa fa-caret-up"></i></a></th>
{% endif %}
{% if seats %}
<th>{% trans "Seat" %} <a href="?{% url_replace request 'ordering' '-seat'%}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'seat'%}"><i class="fa fa-caret-up"></i></a></th>
@@ -99,6 +103,11 @@
{% endif %}
</td>
<td>{{ e.item }}{% if e.variation %} {{ e.variation }}{% endif %}</td>
{% if request.event.has_subevents and not checkinlist.subevent %}
<td>
{{ e.subevent.name }} {{ e.subevent.get_date_range_display }} {{ e.subevent.date_from|date:"TIME_FORMAT" }}
</td>
{% endif %}
{% if seats %}
<td>{{ e.seat|default_if_none:"" }}</td>
{% endif %}

View File

@@ -98,7 +98,9 @@
</td>
{% if request.event.has_subevents %}
{% if cl.subevent %}
<td>{{ cl.subevent.name }} {{ cl.subevent.get_date_range_display }}</td>
<td>
{{ cl.subevent.name }} {{ cl.subevent.get_date_range_display }} {{ cl.subevent.date_from|date:"TIME_FORMAT" }}
</td>
{% else %}
<td>
<em>{% trans "All" %}</em>

View File

@@ -97,6 +97,7 @@
{% bootstrap_field sform.attendee_company_required layout="control" %}
{% bootstrap_field sform.attendee_addresses_asked layout="control" %}
{% bootstrap_field sform.attendee_addresses_required layout="control" %}
{% bootstrap_field sform.checkout_show_copy_answers_button layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "Texts" %}</legend>

View File

@@ -1,5 +1,6 @@
{% extends "pretixcontrol/items/base.html" %}
{% load i18n %}
{% load urlreplace %}
{% block title %}{% trans "Quotas" %}{% endblock %}
{% block inside %}
<h1>{% trans "Quotas" %}</h1>
@@ -41,12 +42,21 @@
<table class="table table-hover table-quotas">
<thead>
<tr>
<th>{% trans "Quota name" %}</th>
<th>{% trans "Quota name" %}
<a href="?{% url_replace request 'ordering' '-name' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'name' %}"><i class="fa fa-caret-up"></i></a></th>
</th>
<th>{% trans "Products" %}</th>
{% if request.event.has_subevents %}
<th>{% trans "Date" context "subevent" %}</th>
<th>{% trans "Date" context "subevent" %}
<a href="?{% url_replace request 'ordering' '-date' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'date' %}"><i class="fa fa-caret-up"></i></a></th>
</th>
{% endif %}
<th>{% trans "Total capacity" %}</th>
<th>{% trans "Total capacity" %}
<a href="?{% url_replace request 'ordering' '-size' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'size' %}"><i class="fa fa-caret-up"></i></a></th>
</th>
<th>{% trans "Capacity left" %}</th>
<th class="action-col-2"></th>
</tr>
@@ -71,7 +81,9 @@
</ul>
</td>
{% if request.event.has_subevents %}
<td>{{ q.subevent.name }} {{ q.subevent.get_date_range_display }}</td>
<td>
{{ q.subevent.name }} {{ q.subevent.get_date_range_display }} {{ q.subevent.date_from|date:"TIME_FORMAT" }}
</td>
{% endif %}
<td>{% if q.size == None %}Unlimited{% else %}{{ q.size }}{% endif %}</td>
<td>{% include "pretixcontrol/items/fragment_quota_availability.html" with availability=q.cached_avail closed=q.closed %}</td>

View File

@@ -62,7 +62,7 @@
<td>
{{ r.payment_provider.verbose_name }}
</td>
<td>{{ o.created|date:"SHORT_DATETIME_FORMAT" }}</td>
<td>{{ r.created|date:"SHORT_DATETIME_FORMAT" }}</td>
<td>{{ r.get_source_display }}</td>
<td>
<span class="label label-{% if r.state == "external" or r.state == "transit" or r.state == "created" %}warning{% elif r.state == "done" %}success{% else %}danger{% endif %}">

View File

@@ -17,6 +17,7 @@
{% bootstrap_field form.name layout="control" %}
{% bootstrap_field form.all_events layout="control" %}
{% bootstrap_field form.limit_events layout="control" %}
{% bootstrap_field form.security_profile layout="control" %}
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}

View File

@@ -508,6 +508,7 @@
{% bootstrap_field form.include_pending layout="control" %}
{% bootstrap_field form.all_products layout="control" %}
{% bootstrap_field form.limit_products layout="control" %}
{% bootstrap_field form.allow_entry_after_exit layout="control" %}
</div>
</div>
{% endfor %}
@@ -536,6 +537,7 @@
{% bootstrap_field cl_formset.empty_form.include_pending layout="control" %}
{% bootstrap_field cl_formset.empty_form.all_products layout="control" %}
{% bootstrap_field cl_formset.empty_form.limit_products layout="control" %}
{% bootstrap_field cl_formset.empty_form.allow_entry_after_exit layout="control" %}
</div>
</div>
{% endescapescript %}

View File

@@ -192,6 +192,7 @@
{% bootstrap_field form.include_pending layout="control" %}
{% bootstrap_field form.all_products layout="control" %}
{% bootstrap_field form.limit_products layout="control" %}
{% bootstrap_field form.allow_entry_after_exit layout="control" %}
</div>
</div>
{% endfor %}
@@ -220,6 +221,7 @@
{% bootstrap_field cl_formset.empty_form.include_pending layout="control" %}
{% bootstrap_field cl_formset.empty_form.all_products layout="control" %}
{% bootstrap_field cl_formset.empty_form.limit_products layout="control" %}
{% bootstrap_field cl_formset.empty_form.allow_entry_after_exit layout="control" %}
</div>
</div>
{% endescapescript %}

View File

@@ -698,6 +698,19 @@ class QuotaList(PaginationMixin, ListView):
if self.request.GET.get("subevent", "") != "":
s = self.request.GET.get("subevent", "")
qs = qs.filter(subevent_id=s)
valid_orders = {
'-date': ('-subevent__date_from', 'name'),
'date': ('subevent__date_from', '-name'),
'size': ('size', 'name'),
'-size': ('-size', '-name'),
'name': ('name',),
'-name': ('-name',),
}
if self.request.GET.get("ordering", "-date") in valid_orders:
qs = qs.order_by(*valid_orders[self.request.GET.get("ordering", "-date")])
return qs
def get_context_data(self, **kwargs):

View File

@@ -8,7 +8,9 @@ from django.contrib import messages
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.files import File
from django.db import transaction
from django.db.models import Count, Max, Min, Prefetch, ProtectedError, Sum
from django.db.models import (
Count, Max, Min, OuterRef, Prefetch, ProtectedError, Subquery, Sum,
)
from django.db.models.functions import Coalesce, Greatest
from django.forms import DecimalField, inlineformset_factory
from django.http import JsonResponse
@@ -30,7 +32,9 @@ from pretix.base.models import (
TeamInvite, User,
)
from pretix.base.models.event import Event, EventMetaProperty, EventMetaValue
from pretix.base.models.giftcards import gen_giftcard_secret
from pretix.base.models.giftcards import (
GiftCardTransaction, gen_giftcard_secret,
)
from pretix.base.models.organizer import TeamAPIToken
from pretix.base.payment import PaymentException
from pretix.base.services.export import multiexport
@@ -967,8 +971,11 @@ class GiftCardListView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi
context_object_name = 'giftcards'
def get_queryset(self):
s = GiftCardTransaction.objects.filter(
card=OuterRef('pk')
).order_by().values('card').annotate(s=Sum('value')).values('s')
qs = self.request.organizer.issued_gift_cards.annotate(
cached_value=Coalesce(Sum('transactions__value'), Decimal('0.00'))
cached_value=Coalesce(Subquery(s), Decimal('0.00'))
).order_by('-issuance')
if self.filter_form.is_valid():
qs = self.filter_form.filter_qs(qs)

View File

@@ -1,5 +1,5 @@
import copy
from datetime import datetime
from datetime import datetime, timedelta
from dateutil.rrule import DAILY, MONTHLY, WEEKLY, YEARLY, rrule, rruleset
from django.contrib import messages
@@ -739,11 +739,15 @@ class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, Crea
se = copy.copy(form.instance)
se.date_from = make_aware(datetime.combine(rdate, t['time_from']), tz)
se.date_to = (
make_aware(datetime.combine(rdate, t['time_to']), tz)
if t.get('time_to')
else None
)
if t.get('time_to'):
se.date_to = (
make_aware(datetime.combine(rdate, t['time_to']), tz)
if t.get('time_to') > t.get('time_from')
else make_aware(datetime.combine(rdate + timedelta(days=1), t['time_to']), tz)
)
else:
se.date_to = None
se.date_admission = (
make_aware(datetime.combine(rdate, t['time_admission']), tz)
if t.get('time_admission')

View File

@@ -114,6 +114,9 @@ class ReauthView(TemplateView):
u = backend.request_authenticate(request)
if u and u == request.user:
next_url = backend.get_next_url(request)
t = int(time.time())
request.session['pretix_auth_login_time'] = t
request.session['pretix_auth_last_used'] = t
if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None):
return redirect(next_url)
return redirect(reverse('control:index'))

View File

@@ -0,0 +1,9 @@
import datetime
import sys
def date_fromisocalendar(isoyear, isoweek, isoday):
if sys.version_info < (3, 8):
return datetime.datetime.strptime(f'{isoyear}-W{isoweek}-{isoday}', "%G-W%V-%u")
else:
return datetime.datetime.fromisocalendar(isoyear, isoweek, isoday)

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-07-30 19:00+0000\n"
"Last-Translator: Abdullah <abdullah.gumaijan@gmail.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -48,16 +48,16 @@ msgstr "إجمالي الإيرادات"
msgid "Contacting Stripe …"
msgstr "الاتصال الشريط ..."
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "مجموع"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "تأكيد الدفع الخاص بك ..."
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "الاتصال البنك الذي تتعامل معه ..."
@@ -366,30 +366,30 @@ msgstr[5] "سيتم إلغاء الحجز تلقائيا بعد {num} دقيقة
msgid "Please enter a quantity for one of the ticket types."
msgstr "الرجاء إدخال كمية التذاكر لأحد أنواع التذاكر."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "من٪ (العملة) ق٪ (سعر) ق"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "من٪ (العملة) ق٪ (سعر) ق"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -45,16 +45,16 @@ msgstr ""
msgid "Contacting Stripe …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr ""
@@ -335,24 +335,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -45,16 +45,16 @@ msgstr ""
msgid "Contacting Stripe …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr ""
@@ -337,24 +337,24 @@ msgstr[2] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"PO-Revision-Date: 2020-05-19 09:19+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-09-15 02:00+0000\n"
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
"da/>\n"
@@ -46,16 +46,16 @@ msgstr "Omsætning i alt"
msgid "Contacting Stripe …"
msgstr "Kontakter Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Total"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Bekræfter din betaling …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Kontakter din bank …"
@@ -312,11 +312,11 @@ msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:755
msgid "Click to close"
msgstr ""
msgstr "Klik for at lukke"
#: pretix/static/pretixcontrol/js/ui/main.js:770
msgid "You have unsaved changes!"
msgstr ""
msgstr "Du har ændringer, der ikke er gemt!"
#: pretix/static/pretixcontrol/js/ui/orderchange.js:25
#, fuzzy
@@ -334,7 +334,7 @@ msgstr "Antal"
#: pretix/static/pretixcontrol/js/ui/question.js:131
msgid "Yes"
msgstr ""
msgstr "Ja"
#: pretix/static/pretixcontrol/js/ui/question.js:132
#, fuzzy
@@ -366,32 +366,32 @@ msgstr[1] "Varerne i din kurv er reserveret for dig i {num} minutter."
msgid "Please enter a quantity for one of the ticket types."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "fra %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "fra %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
msgstr "Tidszone:"
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""
msgstr "Din lokaltid:"
#: pretix/static/pretixpresale/js/widget/widget.js:17
msgctxt "widget"
@@ -452,7 +452,7 @@ msgstr "tilgængelig: %s"
#: pretix/static/pretixpresale/js/widget/widget.js:28
msgctxt "widget"
msgid "Only available with a voucher"
msgstr "Kun tilgængelig med en voucher"
msgstr "Kun tilgængelig med en rabatkode"
#: pretix/static/pretixpresale/js/widget/widget.js:29
#, javascript-format
@@ -497,7 +497,7 @@ msgstr "Fortsæt booking"
#: pretix/static/pretixpresale/js/widget/widget.js:37
msgctxt "widget"
msgid "Redeem a voucher"
msgstr "Indløs voucher"
msgstr "Indløs rabatkode"
#: pretix/static/pretixpresale/js/widget/widget.js:38
msgctxt "widget"
@@ -507,7 +507,7 @@ msgstr "Indløs"
#: pretix/static/pretixpresale/js/widget/widget.js:39
msgctxt "widget"
msgid "Voucher code"
msgstr "Voucherkode"
msgstr "Rabatkode"
#: pretix/static/pretixpresale/js/widget/widget.js:40
msgctxt "widget"
@@ -552,7 +552,7 @@ msgstr "Forrige måned"
#: pretix/static/pretixpresale/js/widget/widget.js:48
msgctxt "widget"
msgid "Next week"
msgstr ""
msgstr "Næste uge"
#: pretix/static/pretixpresale/js/widget/widget.js:49
#, fuzzy
@@ -565,7 +565,7 @@ msgstr "Forrige måned"
#: pretix/static/pretixpresale/js/widget/widget.js:50
msgctxt "widget"
msgid "Open seat selection"
msgstr ""
msgstr "Åbn sædevalg"
#: pretix/static/pretixpresale/js/widget/widget.js:52
msgid "Mo"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-08-25 02:00+0000\n"
"Last-Translator: Dennis Lichtenthäler <lichtenthaeler@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -47,16 +47,16 @@ msgstr "Gesamtumsatz"
msgid "Contacting Stripe …"
msgstr "Kontaktiere Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Gesamt"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Zahlung wird bestätigt …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Kontaktiere Ihre Bank …"
@@ -359,24 +359,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr "Bitte tragen Sie eine Menge für eines der Produkte ein."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "Der Veranstalter behält %(currency)s %(amount)s ein"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr "Sie erhalten %(currency)s %(amount)s zurück"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr "Bitte geben Sie den Betrag ein, den der Veranstalter einbehalten darf."
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr "Zeitzone:"
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr "Deine lokale Zeit:"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-08-25 02:00+0000\n"
"Last-Translator: Dennis Lichtenthäler <lichtenthaeler@rami.io>\n"
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
@@ -47,16 +47,16 @@ msgstr "Gesamtumsatz"
msgid "Contacting Stripe …"
msgstr "Kontaktiere Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Gesamt"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Zahlung wird bestätigt …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Kontaktiere deine Bank …"
@@ -358,24 +358,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr "Bitte trage eine Menge für eines der Produkte ein."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "Der Veranstalter behält %(currency)s %(amount)s ein"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr "Du erhältst %(currency)s %(amount)s zurück"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr "Bitte gib den Betrag ein, den der Veranstalter einbehalten darf."
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr "Zeitzone:"
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr "Deine lokale Zeit:"

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+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,16 +46,16 @@ msgstr ""
msgid "Contacting Stripe …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr ""
@@ -336,24 +336,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2019-10-03 19:00+0000\n"
"Last-Translator: Chris Spy <chrispiropoulou@hotmail.com>\n"
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -47,16 +47,16 @@ msgstr "Συνολικά κέρδη"
msgid "Contacting Stripe …"
msgstr "Επικοινωνία με το Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Σύνολο"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
#, fuzzy
#| msgid "Contacting Stripe …"
msgid "Contacting your bank …"
@@ -376,30 +376,30 @@ msgstr[1] "Τα είδη στο καλάθι θα παραμείνουν δεσ
msgid "Please enter a quantity for one of the ticket types."
msgstr "Εισαγάγετε μια ποσότητα για έναν από τους τύπους εισιτηρίων."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "απο %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "απο %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-04-27 20:00+0000\n"
"Last-Translator: Gonzalo Gabriel Perez <zalitoar@gmail.com>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -47,16 +47,16 @@ msgstr "Ingresos totales"
msgid "Contacting Stripe …"
msgstr "Contactando con Stripe…"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Total"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Confirmando el pago…"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Contactando con el banco…"
@@ -373,30 +373,30 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr "Por favor, introduce un valor para cada tipo de entrada."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "a partir de %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "a partir de %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,9 @@ msgid ""
msgstr ""
"Project-Id-Version: French\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"PO-Revision-Date: 2020-02-26 03:00+0000\n"
"Last-Translator: David100mark <david.hundertmark@gmx.net>\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-09-15 17:00+0000\n"
"Last-Translator: Martin Gross <martin@pc-coholic.de>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
"fr/>\n"
"Language: fr\n"
@@ -46,16 +46,16 @@ msgstr "chiffre d'affaires total"
msgid "Contacting Stripe …"
msgstr "Contacter Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Total"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Confirmation de votre paiment…"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Communication avec votre banque …"
@@ -164,7 +164,7 @@ msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:54
msgid "Product"
msgstr ""
msgstr "Produit"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:58
#, fuzzy
@@ -369,30 +369,30 @@ msgstr[1] "Les articles de votre panier vous sont réservés pour {num} minutes.
msgid "Please enter a quantity for one of the ticket types."
msgstr "SVP entrez une quantité pour un de vos types de billets."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "de %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "de %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-01-24 08:00+0000\n"
"Last-Translator: Prokaj Miklós <mixolid0@gmail.com>\n"
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -47,16 +47,16 @@ msgstr "Teljes bevétel"
msgid "Contacting Stripe …"
msgstr "Kapcsolatfelvétel Stripe-pal…"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Teljes"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "A fizetés megerősítése…"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Kapcsolatfelvétel a bankjával…"
@@ -364,30 +364,30 @@ msgstr[1] "A kosár tartalma {num} percig foglalva van számodra."
msgid "Please enter a quantity for one of the ticket types."
msgstr "Adjon meg egy mennyiséget az egyik jegytípusból."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "%(currency) %(price)-tól"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "%(currency) %(price)-tól"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-06-12 20:00+0000\n"
"Last-Translator: Frank <webappconcept@gmail.com>\n"
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -47,16 +47,16 @@ msgstr "Ricavi totali"
msgid "Contacting Stripe …"
msgstr "Sto contattando Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Totale"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Stiamo processando il tuo pagamento..."
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Sto contattando la tua banca …"
@@ -363,24 +363,24 @@ msgstr[1] "Gli elementi nel tuo carrello sono riservati per {num} minuti."
msgid "Please enter a quantity for one of the ticket types."
msgstr "Inserisci la quantità per una tipologia di biglietto."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "L'organizzatore trattiene %(currency)s %(amount)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr "Ricevi indietro %(currency)s %(amount)s"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr "Inserisci l'importo che l'organizzatore può trattenere."
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2019-11-13 06:00+0000\n"
"Last-Translator: Zane Smite <z.smite@riga-jurmala.com>\n"
"Language-Team: Latvian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -48,16 +48,16 @@ msgstr "Apgrozījums kopā"
msgid "Contacting Stripe …"
msgstr "Savienojas ar Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Kopā"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Jūsu maksājums tiek apstrādāts …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Tiek veidots savienojums ar jūsu banku …"
@@ -374,30 +374,30 @@ msgstr[2] "Preces jūsu grozā ir rezervētas uz {num} minūtēm."
msgid "Please enter a quantity for one of the ticket types."
msgstr "Lūdzu, ievadiet nepieciešamo daudzumu izvēlētajam biļešu veidam."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "no %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
#, fuzzy
#| msgctxt "widget"
#| msgid "from %(currency)s %(price)s"
msgid "You get %(currency)s %(amount)s back"
msgstr "no %(currency)s %(price)s"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+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,16 +46,16 @@ msgstr ""
msgid "Contacting Stripe …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr ""
@@ -336,24 +336,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: 2020-08-05 06:00+0000\n"
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -46,16 +46,16 @@ msgstr "Totaalomzet"
msgid "Contacting Stripe …"
msgstr "Verbinding maken met Stripe …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr "Totaal"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr "Betaling bevestigen …"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr "Verbinding maken met uw bank …"
@@ -351,24 +351,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr "Voer een hoeveelheid voor een van de producten in."
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "De organisator houdt %(currency)s %(amount)s"
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr "U krijgt %(currency)s %(amount)s terug"
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr "Voer het bedrag in dat de organisator mag houden."
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr "Tijdzone:"
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
msgstr "Uw lokale tijd:"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-14 12:00+0000\n"
"POT-Creation-Date: 2020-10-13 16:13+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -45,16 +45,16 @@ msgstr ""
msgid "Contacting Stripe …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:57
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:60
msgid "Total"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:146
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:177
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:152
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:183
msgid "Confirming your payment …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:153
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:159
msgid "Contacting your bank …"
msgstr ""
@@ -335,24 +335,24 @@ msgstr[1] ""
msgid "Please enter a quantity for one of the ticket types."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:387
#: pretix/static/pretixpresale/js/ui/main.js:386
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:395
#: pretix/static/pretixpresale/js/ui/main.js:394
msgid "You get %(currency)s %(amount)s back"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:411
#: pretix/static/pretixpresale/js/ui/main.js:410
msgid "Please enter the amount the organizer can keep."
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:425
#: pretix/static/pretixpresale/js/ui/main.js:438
#: pretix/static/pretixpresale/js/ui/main.js:424
#: pretix/static/pretixpresale/js/ui/main.js:437
msgid "Time zone:"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:430
#: pretix/static/pretixpresale/js/ui/main.js:429
msgid "Your local time:"
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