forked from CGM_Public/pretix_original
Compare commits
76
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f9f2443e9 | ||
|
|
1647c82be1 | ||
|
|
981a445b49 | ||
|
|
6d883fc37d | ||
|
|
3c46c461c0 | ||
|
|
ee70fec7ad | ||
|
|
69c2a1b3c2 | ||
|
|
c2ababb9d6 | ||
|
|
db9049130c | ||
|
|
65b74d0483 | ||
|
|
c21083bf80 | ||
|
|
47c281aaa6 | ||
|
|
e73e5e0340 | ||
|
|
1cb38e279c | ||
|
|
d8500128ea | ||
|
|
27e042baf7 | ||
|
|
d7aa94d6ae | ||
|
|
c0007a9566 | ||
|
|
c45da95237 | ||
|
|
45d17728d4 | ||
|
|
c4c81742d5 | ||
|
|
4708509585 | ||
|
|
99b5f3cc3b | ||
|
|
dad3de9cd3 | ||
|
|
3566fc877a | ||
|
|
77ff0298f1 | ||
|
|
22301f5429 | ||
|
|
25a83adc78 | ||
|
|
9dc1328b47 | ||
|
|
5d28e5a959 | ||
|
|
4ff07d12a6 | ||
|
|
5688293288 | ||
|
|
9b77403796 | ||
|
|
c93c2fb6e8 | ||
|
|
5800babdab | ||
|
|
5e3600ac44 | ||
|
|
3af2342d7b | ||
|
|
3d68c83907 | ||
|
|
6366df2c24 | ||
|
|
05ca336c1b | ||
|
|
f643102696 | ||
|
|
33ef50daea | ||
|
|
8071207bf3 | ||
|
|
767bb27175 | ||
|
|
b7f240faf0 | ||
|
|
e0e2b2d7f7 | ||
|
|
10b515f1d1 | ||
|
|
d81c05c444 | ||
|
|
bc0a205f03 | ||
|
|
0e53ddc83b | ||
|
|
0400b577bb | ||
|
|
ec2085f125 | ||
|
|
6430427e3a | ||
|
|
38a1b6a417 | ||
|
|
764d7a2f1c | ||
|
|
e65564234f | ||
|
|
1ec18eb44a | ||
|
|
4c51c28d7a | ||
|
|
eaa134089e | ||
|
|
a015c9ca2a | ||
|
|
d8ca865fc6 | ||
|
|
987b02d733 | ||
|
|
3dd8d4349d | ||
|
|
fd43908e4c | ||
|
|
257ed8ebc3 | ||
|
|
dfd8bf1c0f | ||
|
|
0f709c2275 | ||
|
|
3b64e6046c | ||
|
|
26cbc24a10 | ||
|
|
33a5479809 | ||
|
|
000c64755d | ||
|
|
b32249d48b | ||
|
|
c325cc1120 | ||
|
|
8d2791b32e | ||
|
|
466fc15382 | ||
|
|
86cf3be225 |
@@ -565,6 +565,8 @@ organizer level.
|
||||
.. warning:: This API is intended for advanced users. Even though we take care to validate your input, you will be
|
||||
able to break your event using this API by creating situations of conflicting settings. Please take care.
|
||||
|
||||
.. note:: When authenticating with :ref:`rest-deviceauth`, only a limited subset of settings is available.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/settings/
|
||||
|
||||
Get current values of event settings.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.. spelling:word-list:: checkin
|
||||
|
||||
.. _rest-exporters:
|
||||
|
||||
Data exporters
|
||||
==============
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ at :ref:`plugin-docs`.
|
||||
webhooks
|
||||
seatingplans
|
||||
exporters
|
||||
scheduled_exports
|
||||
shredders
|
||||
sendmail_rules
|
||||
billing_invoices
|
||||
|
||||
@@ -18,6 +18,8 @@ default_price money (string) The price set d
|
||||
price money (string) The price used for this variation. This is either the
|
||||
same as ``default_price`` if that value is set or equal
|
||||
to the item's ``default_price`` (read-only).
|
||||
free_price_suggestion money (string) A suggested price, used as a default value if
|
||||
``Item.free_price`` is set (or ``null``).
|
||||
original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
active boolean If ``false``, this variation will not be sold or shown.
|
||||
@@ -53,6 +55,10 @@ meta_data object Values set for
|
||||
|
||||
The ``meta_data`` and ``checkin_attention`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 2023.10
|
||||
|
||||
The ``free_price_suggestion`` attribute has been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -103,6 +109,7 @@ Endpoints
|
||||
"default_price": "223.00",
|
||||
"price": 223.0,
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"meta_data": {}
|
||||
},
|
||||
{
|
||||
@@ -116,10 +123,16 @@ Endpoints
|
||||
"require_membership": false,
|
||||
"require_membership_hidden": false,
|
||||
"require_membership_types": [],
|
||||
"sales_channels": ["web"],
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hide_without_voucher": false,
|
||||
"description": {},
|
||||
"position": 1,
|
||||
"default_price": null,
|
||||
"price": 15.0,
|
||||
"default_price": "223.00",
|
||||
"price": 223.0,
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"meta_data": {}
|
||||
}
|
||||
]
|
||||
@@ -163,6 +176,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -231,6 +245,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -291,6 +306,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": false,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
|
||||
@@ -29,6 +29,8 @@ free_price boolean If ``true``,
|
||||
they buy the product (however, the price can't be set
|
||||
lower than the price defined by ``default_price`` or
|
||||
otherwise).
|
||||
free_price_suggestion money (string) A suggested price, used as a default value if
|
||||
``free_price`` is set (or ``null``).
|
||||
tax_rate decimal (string) The VAT rate to be applied for this item (read-only,
|
||||
set through ``tax_rule``).
|
||||
tax_rule integer The internal ID of the applied tax rule (or ``null``).
|
||||
@@ -50,9 +52,12 @@ available_from datetime The first dat
|
||||
(or ``null``).
|
||||
available_until datetime The last date time at which this item can be bought
|
||||
(or ``null``).
|
||||
hidden_if_available integer The internal ID of a quota object, or ``null``. If
|
||||
hidden_if_available integer **DEPRECATED** The internal ID of a quota object, or ``null``. If
|
||||
set, this item won't be shown publicly as long as this
|
||||
quota is available.
|
||||
hidden_if_item_available integer The internal ID of a different item, or ``null``. If
|
||||
set, this item won't be shown publicly as long as this
|
||||
other item is available.
|
||||
require_voucher boolean If ``true``, this item can only be bought using a
|
||||
voucher that is specifically assigned to this item.
|
||||
hide_without_voucher boolean If ``true``, this item is only shown during the voucher
|
||||
@@ -123,6 +128,8 @@ variations list of objects A list with o
|
||||
├ price money (string) The price used for this variation. This is either the
|
||||
same as ``default_price`` if that value is set or equal
|
||||
to the item's ``default_price``.
|
||||
├ free_price_suggestion money (string) A suggested price, used as a default value if
|
||||
``free_price`` is set (or ``null``).
|
||||
├ original_price money (string) An original price, shown for comparison, not used
|
||||
for price calculations (or ``null``).
|
||||
├ active boolean If ``false``, this variation will not be sold or shown.
|
||||
@@ -196,6 +203,15 @@ meta_data object Values set fo
|
||||
|
||||
The ``media_policy`` and ``media_type`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 2023.10
|
||||
|
||||
The ``free_price_suggestion`` and ``variations[x].free_price_suggestion`` attributes have been added.
|
||||
|
||||
.. versionchanged:: 2023.10
|
||||
|
||||
The ``hidden_if_item_available`` attributes has been added, the ``hidden_if_available`` attribute has been
|
||||
deprecated.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
@@ -246,6 +262,7 @@ Endpoints
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"free_price_suggestion": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
@@ -259,6 +276,7 @@ Endpoints
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"hidden_if_item_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
@@ -291,6 +309,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -309,6 +328,7 @@ Endpoints
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -377,6 +397,7 @@ Endpoints
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"free_price_suggestion": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
@@ -390,6 +411,7 @@ Endpoints
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"hidden_if_item_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
@@ -422,6 +444,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -440,6 +463,7 @@ Endpoints
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -489,6 +513,7 @@ Endpoints
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"free_price_suggestion": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
@@ -502,6 +527,7 @@ Endpoints
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"hidden_if_item_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
@@ -533,6 +559,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -551,6 +578,7 @@ Endpoints
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -588,6 +616,7 @@ Endpoints
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"free_price_suggestion": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
@@ -601,6 +630,7 @@ Endpoints
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"hidden_if_item_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"allow_cancel": true,
|
||||
@@ -633,6 +663,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -651,6 +682,7 @@ Endpoints
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -719,6 +751,7 @@ Endpoints
|
||||
"active": true,
|
||||
"description": null,
|
||||
"free_price": false,
|
||||
"free_price_suggestion": null,
|
||||
"tax_rate": "0.00",
|
||||
"tax_rule": 1,
|
||||
"admission": false,
|
||||
@@ -732,6 +765,7 @@ Endpoints
|
||||
"available_from": null,
|
||||
"available_until": null,
|
||||
"hidden_if_available": null,
|
||||
"hidden_if_item_available": null,
|
||||
"require_voucher": false,
|
||||
"hide_without_voucher": false,
|
||||
"generate_tickets": null,
|
||||
@@ -764,6 +798,7 @@ Endpoints
|
||||
"default_price": "10.00",
|
||||
"price": "10.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
@@ -782,6 +817,7 @@ Endpoints
|
||||
"default_price": null,
|
||||
"price": "23.00",
|
||||
"original_price": null,
|
||||
"free_price_suggestion": null,
|
||||
"active": true,
|
||||
"checkin_attention": false,
|
||||
"require_approval": false,
|
||||
|
||||
@@ -348,7 +348,7 @@ Endpoints
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/questions/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
@@ -415,7 +415,7 @@ Endpoints
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the question to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The item could not be modified due to invalid submitted data
|
||||
:statuscode 400: The question could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
@@ -427,7 +427,7 @@ Endpoints
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/ HTTP/1.1
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/questions/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
@@ -440,7 +440,7 @@ Endpoints
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the item to delete
|
||||
:param id: The ``id`` field of the question to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
@@ -0,0 +1,556 @@
|
||||
.. spelling:word-list:: checkin
|
||||
|
||||
Scheduled data exports
|
||||
======================
|
||||
|
||||
pretix and it's plugins include a number of data exporters that allow you to bulk download various data from pretix in
|
||||
different formats. You should read :ref:`rest-exporters` first to get an understanding of the basic mechanism.
|
||||
|
||||
Exports can be scheduled to be sent at specific times automatically, both on organizer level and event level.
|
||||
|
||||
Scheduled export resource
|
||||
-------------------------
|
||||
|
||||
The scheduled export contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the schedule
|
||||
owner string Email address of the user who created this schedule (read-only).
|
||||
This address will always receive the export and the export
|
||||
will only contain data that this user has permission
|
||||
to access at the time of the export. **We consider this
|
||||
field experimental, it's behaviour might change in the future.
|
||||
Note that the email address of a user can change at any time.**
|
||||
export_identifier string Identifier of the export to run, see :ref:`rest-exporters`
|
||||
export_form_data object Input data for the export, format depends on the export,
|
||||
see :ref:`rest-exporters` for more details.
|
||||
locale string Language to run the export in
|
||||
mail_additional_recipients string Email addresses to receive the export, comma-separated (or empty string)
|
||||
mail_additional_recipients_cc string Email addresses to receive the export in copy, comma-separated (or empty string)
|
||||
mail_additional_recipients_bcc string Email addresses to receive the exportin blind copy, comma-separated (or empty string)
|
||||
mail_subject string Subject to use for the email (currently no variables supported)
|
||||
mail_template string Text to use for the email (currently no variables supported)
|
||||
schedule_rrule string Recurrence specification to determine the **days** this
|
||||
schedule runs on in ``RRULE`` syntax following `RFC 5545`_
|
||||
with some restrictions. Only one rule is allowed, only
|
||||
one occurrence per day is allowed, and some features
|
||||
are not supported (``BYMONTHDAY``, ``BYYEARDAY``,
|
||||
``BYEASTER``, ``BYWEEKNO``).
|
||||
schedule_rrule_time time Time of day to run this on on the specified days.
|
||||
Will be interpreted as local time of the event for event-level
|
||||
exports. For organizer-level exports, the timezone is given
|
||||
in the field ``timezone``. The export will never run **before**
|
||||
this time but it **may** run **later**.
|
||||
timezone string Time zone to interpret the schedule in (only for organizer-level exports)
|
||||
schedule_next_run datetime Next planned execution (read-only, computed by server)
|
||||
error_counter integer Number of consecutive times this export failed (read-only).
|
||||
After a number of failures (currently 5), the schedule no
|
||||
longer is executed. Changing parameters resets the value.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Special notes on permissions
|
||||
----------------------------
|
||||
|
||||
Permission handling for scheduled exports is more complex than for most other objects. The reason for this is that
|
||||
there are two levels of access control involved here: First, you need permission to access or change the configuration
|
||||
of the scheduled exports in the moment you are doing it. Second, you **continuously** need permission to access the
|
||||
**data** that is exported as part of the schedule. For this reason, scheduled exports always need one user account
|
||||
to be their **owner**.
|
||||
|
||||
Therefore, scheduled exports **must** be created by an API client using :ref:`OAuth authentication <rest-oauth>`.
|
||||
It is impossible to create a scheduled export using token authentication. After the export is created, it can also be
|
||||
modified using token authentication.
|
||||
|
||||
A user or token with the "can change settings" permission for a given organizer or event can see and change
|
||||
**all** scheduled exports created for the respective organizer or event, regardless of who created them.
|
||||
A user without this permission can only see **their own** scheduled exports.
|
||||
A token without this permission can not see scheduled exports as all.
|
||||
|
||||
|
||||
|
||||
Endpoints for event exports
|
||||
---------------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/scheduled_exports/
|
||||
|
||||
Returns a list of all scheduled exports the client has access to.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/scheduled_exports/ 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": [
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"error_counter": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id``, ``export_identifier``, and ``schedule_next_run``.
|
||||
Default: ``id``
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/scheduled_exports/(id)/
|
||||
|
||||
Returns information on one scheduled export, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/scheduled_exports/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
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"error_counter": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param id: The ``id`` field of the scheduled export to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/scheduled_exports/
|
||||
|
||||
Schedule a new export.
|
||||
|
||||
.. note:: See above for special notes on permissions.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/scheduled_exports/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"error_counter": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create an item for
|
||||
:param event: The ``slug`` field of the event to create an item for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The item could not be created due to invalid submitted data.
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create this resource.
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/scheduled_exports/(id)/
|
||||
|
||||
Update a scheduled export. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/scheduled_exports/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_this"},
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_this"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"error_counter": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the export to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The export could not be modified due to invalid submitted data
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/scheduled_exports/(id)/
|
||||
|
||||
Delete a scheduled export.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/scheduled_exports/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param event: The ``slug`` field of the event to modify
|
||||
:param id: The ``id`` field of the export to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
Endpoints for organizer exports
|
||||
---------------------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/scheduled_exports/
|
||||
|
||||
Returns a list of all scheduled exports the client has access to.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/scheduled_exports/ 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": [
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"timezone": "Europe/Berlin",
|
||||
"error_counter": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``id``, ``export_identifier``, and ``schedule_next_run``.
|
||||
Default: ``id``
|
||||
: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)/scheduled_exports/(id)/
|
||||
|
||||
Returns information on one scheduled export, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/scheduled_exports/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
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"timezone": "Europe/Berlin",
|
||||
"error_counter": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param id: The ``id`` field of the scheduled export 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)/scheduled_exports/
|
||||
|
||||
Schedule a new export.
|
||||
|
||||
.. note:: See above for special notes on permissions.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/scheduled_exports/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"timezone": "Europe/Berlin"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_previous"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"timezone": "Europe/Berlin",
|
||||
"error_counter": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create an item for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The item 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)/scheduled_exports/(id)/
|
||||
|
||||
Update a scheduled export. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
|
||||
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
|
||||
want to change.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/scheduled_exports/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_this"},
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"owner": "john@example.com",
|
||||
"export_identifier": "orderlist",
|
||||
"export_form_data": {"_format": "xlsx", "date_range": "week_this"},
|
||||
"locale": "en",
|
||||
"mail_additional_recipients": "mary@example.org",
|
||||
"mail_additional_recipients_cc": "",
|
||||
"mail_additional_recipients_bcc": "",
|
||||
"mail_subject": "Order list",
|
||||
"mail_template": "Here is last week's order list\n\nCheers\nJohn",
|
||||
"schedule_rrule": "DTSTART:20230118T000000\nRRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH",
|
||||
"schedule_rrule_time": "04:00:00",
|
||||
"schedule_next_run": "2023-10-26T02:00:00Z",
|
||||
"timezone": "Europe/Berlin",
|
||||
"error_counter": 0
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the export to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The export 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.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/scheduled_exports/(id)/
|
||||
|
||||
Delete a scheduled export.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/scheduled_exports/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to modify
|
||||
:param id: The ``id`` field of the export to delete
|
||||
:statuscode 204: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
|
||||
.. _RFC 5545: https://datatracker.ietf.org/doc/html/rfc5545#section-3.8.5.3
|
||||
@@ -24,3 +24,4 @@ If you want to **create** a plugin, please go to the
|
||||
imported_secrets
|
||||
webinar
|
||||
presale-saml
|
||||
kulturpass
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
KulturPass
|
||||
=========
|
||||
|
||||
.. note::
|
||||
|
||||
Since the KulturPass is specific to event organizers within Germany, the following page is also only provided in
|
||||
German. Should you require assistance with the KulturPass and do not speak this language, please feel free reach
|
||||
out to support@pretix.eu.
|
||||
|
||||
|
||||
Einführung
|
||||
----------
|
||||
Der `KulturPass`_ ist ein Angebot der Bundesregierung für alle, die im laufenden Jahr ihren 18. Geburtstag feiern.
|
||||
Sie erhalten ab ihrem 18. Geburtstag ein Budget von 200 Euro, das sie für Eintrittskarten, Bücher, CDs, Platten und
|
||||
vieles andere einsetzen können. So wird Kultur vor Ort noch einfacher erlebbar. Gleichzeitig stärkt das die Nachfrage
|
||||
bei den Anbietenden.
|
||||
|
||||
Da pretix ein Ticketing-System ist, stellen wir ausschließlich einen automatisierten Prozess für den Verkauf von
|
||||
Eintrittskarten über den KulturPass-Marktplatz bereit.
|
||||
|
||||
|
||||
Registrierung und Einrichtung
|
||||
-----------------------------
|
||||
Um als Unternehmen oder Kultureinrichtung Angebote auf dem KulturPass-Marktplatz anbieten zu können, ist zunächst eine
|
||||
Registerung und die Einrichtung eines "Shops" sowie der dazugehörigen Angebote notwendig.
|
||||
|
||||
1. Registrierung
|
||||
Registrieren Sie sich zunächst unter https://www.kulturpass.de/anbietende/layer als Anbieter. Im Zuge der
|
||||
Registrierung beantworten Sie einige Fragen zu Ihrem Unternehmen/Ihrer Kultureinrichtung, hinterlegen Ihre
|
||||
E-Mail-Adresse und beantworten Fragen zu Ihren Angebotsformen sowie Finanzierung Ihrer Einrichtung.
|
||||
|
||||
2. Anlegen eines KulturPass Shops
|
||||
Nach Ihrer Registrierung müssen Sie der Weitergabe Ihrer Daten an die technische Platform hinter dem KulturPass,
|
||||
Mirakl, zustimmen. Hier benennen Sie auch Ihren Shop.
|
||||
|
||||
3. Identifizierung mit ELSTER-Zertifikat
|
||||
Als nächsten Schritt müssen Sie Ihr Unternehmen oder Ihre Einrichtung mit Hilfe eines sog. ELSTER-Zertifikates
|
||||
identifizieren. Dieses Zertifikat nutzen Sie auch bereits jetzt schon, wenn Sie auf elektronischem Wege mit der
|
||||
Finanzverwaltung kommunizieren.
|
||||
|
||||
4. Ersteinrichtung in pretix
|
||||
Hinterlegen Sie nun die ID-Nummer Ihres KulturPass Marktplatz-Shops sowie einen API-Key in den
|
||||
`Einstellungen Ihres Veranstalterkontos`_ (Veranstalter-Konto -> Einstellungen -> KulturPass). Diese Daten müssen
|
||||
Sie nur einmalig für alle Ihre Veranstaltungen angeben.
|
||||
|
||||
Im `KulturPass-Backend`_ finden Sie die benötigten Informationen indem Sie auf das Benutzer-Symbol in der oberen,
|
||||
rechten Ecke klicken, "Profil" und dann "API Schlüssel" auswählen bzw. indem Sie auf "Einstellungen" in der
|
||||
Navigation links und dann "Shop" auswählen.
|
||||
|
||||
.. note::
|
||||
|
||||
Zu jedem Zeitpunkt kann nur ein Hintergrundsystem mit dem KulturPass-System verbunden sein. Werden
|
||||
unterschiedliche Systeme oder gar mehrere pretix-Veranstalterkonten mit dem gleichen KulturPass-System verbunden,
|
||||
können keine Bestellungen mehr verarbeitet werden und Angebote nicht automatisiert an den KulturPass-Marktplatz
|
||||
übermittelt werden. Eingehende Bestellungen von Jugendlichen werden in diesem Fall automatisch abgelehnt, da diese
|
||||
nicht eindeutig zugeordnet werden können. Ebenso überschreibt die Bereitstellung der Angebote eines Systems die
|
||||
Angebote eines anderen Systems.
|
||||
|
||||
Wenn Sie mehrere Systeme haben, die den KulturPass-Marktplatz bedienen sollen, wenden Sie sich bitte an den
|
||||
KulturPass-Support, um sich einen weiteren Shop einrichten zu lassen.
|
||||
|
||||
5. Aktivierung der KulturPass-Erweiterungen
|
||||
Alle Veranstaltungen, die Sie über den KulturPass anbieten möchten, benötigen die `KulturPass-Erweiterung`_.
|
||||
Aktivieren Sie diese bitte in jeder relevanten Veranstaltung über Einstellungen -> Erweiterungen -> Tab
|
||||
"Integrationen" -> KulturPass.
|
||||
|
||||
6. Konfiguration der Artikel
|
||||
Nachdem die KulturPass-Erweiterung aktiviert wurde, müssen Sie sich entscheiden, welche Produkte Sie über den
|
||||
KulturPass-Marktplatz anbieten möchten. In der Bearbeitungs-Ansicht des jeweiligen Produktes finden Sie hierzu im
|
||||
Tab "Zusätzliche Einstellungen" eine Checkbox "Das Produkt kann mit dem KulturPass erworben werden".
|
||||
|
||||
.. note::
|
||||
|
||||
Die Eigenschaft, dass ein Produkt durch den KulturPass-Marktplatz erworben werden kann, kann für beliebig viele
|
||||
Produkte aktiviert werden. Auf Grund der Funktionsweise des KulturPasses sollten Sie jedoch gerade bei vielen
|
||||
Artikeln mit unterschiedlich hohen Preisen darauf achten, dass die Preisspanne nicht zu hoch ausfällt.
|
||||
|
||||
Aktivieren Sie die Option für drei Produkte für 1, 10 und 100 Euro, so wird Ihr Angebot im KulturPass-Marktplatz
|
||||
für 100 Euro gelistet werden. Dies bedeutet im Umkehrschluss auch, dass das KulturPass-Guthaben eines Jugendlichen
|
||||
auch mindestens 100 Euro betragen muss, damit er Ihr Angebot in Anspruch nehmen kann - auch wenn die betroffene
|
||||
Person lediglich das 1 Euro-Angebot wahrnehmen möchte. Erst mit dem 100 Euro KulturPass-Einlösecode wählt die
|
||||
kaufende Person in Ihrem pretix-Shop aus, welches Produkt erworben werden soll. Ein Restguthaben wird nach dem Kauf
|
||||
automatisch zurückerstattet und dem KulturPass-Konto wieder gutgeschrieben.
|
||||
|
||||
7. Konfiguration des Marktplatz-Eintrages
|
||||
Je nach dem, ob es sich bei Ihrer Veranstaltung um eine Einzelveranstaltung oder eine Veranstaltungsreihe handelt,
|
||||
müssen Sie die folgende Einstellung einmalig oder pro Veranstaltungstermin vornehmen.
|
||||
|
||||
Einzelveranstaltungen konfigurieren Sie über den Menüpunkt "KulturPass" in den Einstellungen Ihrer Veranstaltung;
|
||||
Veranstaltungsreihen beim Anlegen oder Editieren eines jeden einzelnen Termins am Ende der Seite.
|
||||
|
||||
Um eine Veranstaltung oder einen Veranstaltungstermin im KulturPass-Marktplatz anzubieten, aktivieren Sie zunächst
|
||||
die Option "Diese Veranstaltung via KulturPass anbieten". Geben Sie im folgenden die benötigten Informationen an.
|
||||
|
||||
Bitte beachten Sie, dass Sie bei den Angaben präzise Titel und Beschreibungen verwenden, da der KulturPass-
|
||||
Marktplatz ausschließlich die Informationen aus diesem Bereich verwendet. Etwaige andere Informationen die Sie
|
||||
bspw. in den "Text auf Startseite"-Felder eingeben haben, erreichen das KulturPass-System nicht.
|
||||
|
||||
.. note::
|
||||
|
||||
Gerade bei Veranstaltungsreihen nutzen viele pretix-Veranstalter gerne verkürzte Termin-Namen. Ein Schwimmbad würde
|
||||
beispielsweise Ihre Veranstaltungsreihe "Freibad Musterstadt" und die einzelnen Termine nur "Schwimmen" nennen.
|
||||
|
||||
Während dies im pretix-Shop in einem gemeinsamen Kontext wunderbar funktioniert, würde eine Veranstaltung mit dem
|
||||
Titel "Schwimmen" im KulturPass-Marktplatz Informationen vermissen lassen. Wählen Sie daher für das Eingabefeld
|
||||
"Veranstaltungstitel" in der KulturPass-Konfiguration einen sprechenden Wert.
|
||||
|
||||
8. Übermittlung der Angebote
|
||||
Sobald Sie Ihre ersten Veranstaltungen konfiguriert und live geschaltet haben, übermittelt pretix automatisch in
|
||||
regelmäßigen Abständen alle von Ihnen angebotenen Veranstaltungen an das KulturPass System (Mirakl). Bitte beachten
|
||||
Sie jedoch, dass der Import der Produkte und Angebote einige Zeit in Anspruch nehmen kann. Zum einen müssen
|
||||
Angebote initial händisch von den Betreibern der KulturPass-Platform freigegeben werden, zum anderen muss auch eine
|
||||
Synchronisation zwischen dem Hintergrundsystem und der KulturPass-App erfolgen. Auf die Dauer dieser Prozesse hat
|
||||
pretix keinen Einfluss.
|
||||
|
||||
9. Freischalten des Marktplatz-Shops
|
||||
Nachdem pretix erstmalig Angebote an das KulturPass-System übermittelt hat, müssen Sie Ihren Shop KulturPass-Shop
|
||||
einmalig freischalten. Loggen Sie sich hierzu in das `KulturPass-Backend`_ ein.
|
||||
|
||||
|
||||
Verwalten von KulturPass-Bestellungen
|
||||
-------------------------------------
|
||||
Durch die Nutzung der pretix-Integration mit dem KulturPass-System müssen Sie sich - bis auf die Kennzeichnung von
|
||||
Produkten, die per KulturPass erworben werden dürfen, sowie die Bereitstellung von Veranstaltungs-Informationen für den
|
||||
KulturPass-Marktplatz - um nichts kümmern: pretix übermittelt automatisch Ihre Veranstaltungen, wickelt die Einlösung
|
||||
der Tickets ab und führt die Abrechnung mit dem Hintergrund-System durch.
|
||||
|
||||
Für Ihre Kunden verhält sich der KulturPass wie eine Zahlungsmethode im Bestellprozess und wird dort neben Ihren
|
||||
anderen Zahlungsmethoden mit angeboten.
|
||||
|
||||
Die Gelder für mit dem KulturPass bezahlte Tickets erhalten Sie in Form einer Sammel-Überweisung von der Stiftung
|
||||
Digitale Chancen auf das von Ihnen beim KulturPass Onboarding angegeben Bankkonto.
|
||||
|
||||
In Ihrem `KulturPass-Backend`_ können Sie über den Menüpunkt "Buchhaltung" Ihre bereits erfolgten und kommenden
|
||||
Auszahlungen betrachten.
|
||||
|
||||
.. note::
|
||||
|
||||
Es ist von äußerster Wichtigkeit, dass Sie weder die eingehenden Bestellungen noch die Produkte und Angebote im
|
||||
KulturPass-Backend händisch bearbeiten - auch wenn dies möglich wäre.
|
||||
|
||||
Bei händischen Änderungen riskieren Sie, dass die Datenbasis zwischen pretix und dem KulturPass-System divergiert
|
||||
und es zu fehlerhaften Buchungen kommt. Wann immer möglich, sollten Sie Korrekturbuchungen und Änderungen
|
||||
ausschließlich über pretix vornehmen.
|
||||
|
||||
Sollte eine händische Änderung/Korrektur notwendig werden, wenden Sie sich bitte an den pretix-Support, damit wir
|
||||
die Auswirkungen evaluieren und vorab mit Ihnen besprechen können!
|
||||
|
||||
Erstattungen für Stornos und Absagen können Sie wie gehabt über das pretix-Backend vornehmen. Der jeweilige Betrag wird
|
||||
dem KulturPass-Konto dann automatisch gutgeschrieben.
|
||||
|
||||
Da nach Ausgabe eines KulturPass Einlöse-Codes dieser vom Kunden jederzeit oder vom System bei
|
||||
Nicht-(Komplett)Einlösung binnen 48 Stunden storniert werden kann, kann das im KulturPass-Backend angezeigte,
|
||||
auszuzahlende Guthaben fluktuieren. Da in der Regel Auszahlungen frühestens 48 Stunden nach der Aufgabe einer
|
||||
KulturPass-Bestellungen erfolgen, sollte Ihr Guthaben in der Regel nicht ins Negative gehen.
|
||||
|
||||
Ablauf für Kunden
|
||||
-----------------
|
||||
Ihre Kunden erhalten - nachdem sie sich ein eigenes Konto in der KulturPass-App angelegt und sich mit ihrem
|
||||
elektronischen Personalausweis identifiziert haben - ein Guthaben von 200 Euro, welches für Leistungen aus dem
|
||||
KulturPass-Marktplatz eingelöst werden kann.
|
||||
|
||||
Im Falle von Veranstaltungen, die per pretix verkauft werden, wählt der Kunde ein Angebot aus und erhält im folgenden
|
||||
binnen kurzer Zeit (ca. 10-20 Minuten) einen Code und einen Link, um diesen einzulösen. Der Link bringt den Kunden direkt auf die Seite der
|
||||
betreffenden pretix-Veranstaltung. Hier wird der Kunde darauf hingewiesen, für welche Produkte der Code genutzt werden
|
||||
kann.
|
||||
|
||||
Im Bezahlschritt des Verkaufsprozesses wird dem Kunden vorgeschlagen, seinen KulturPass Einlösecode nun zu nutzen, um
|
||||
die gewünschte Leistung zu erhalten.
|
||||
|
||||
Wurde ein Artikel gewählt, welcher günstiger als der Wert des Einlösecodes war, wird das Restguthaben automatisch auf
|
||||
das KulturPass-Konto erstattet.
|
||||
|
||||
Wurden hingegen mehrere Artikel in den Warenkorb gelegt, so kann die Differenz mit einem anderen, regulären
|
||||
Zahlungsmittel erfolgen.
|
||||
|
||||
Einlösecodes, die vom Kunden nicht binnen 48 Stunden eingelöst werden, werden automatisch storniert und dem
|
||||
KulturPass-Konto wieder gutgeschrieben. Dieser Mechanismus greift auch, wenn eine Veranstaltung mittlerweile
|
||||
ausverkauft ist und daher der Einlösecode nicht mehr Nutzbar ist.
|
||||
|
||||
|
||||
Unterstützung
|
||||
-------------
|
||||
Weitergehende Informationen zum KulturPass finden Sie auch auf der `Webseite des KulturPasses`_, sowie im
|
||||
`KulturPass Serviceportal`_.
|
||||
|
||||
|
||||
.. _KulturPass: https://www.kulturpass.de/
|
||||
.. _Einstellungen Ihres Veranstalterkontos: https://pretix.eu/control/organizer/-/settings/kulturpass
|
||||
.. _KulturPass-Erweiterung: https://pretix.eu/control/event/-/-/settings/plugins#tab-0-2-open
|
||||
.. _KulturPass-Backend: https://kulturpass-de.mirakl.net/
|
||||
.. _Webseite des KulturPasses: https://www.kulturpass.de/
|
||||
.. _KulturPass Serviceportal: https://service.kulturpass.de/help/
|
||||
@@ -196,6 +196,10 @@ settings. For example, if you set up a meta data property called "Promoted" that
|
||||
|
||||
<pretix-widget event="https://pretix.eu/demo/series/" list-type="list" filter="attr[Promoted]=Yes"></pretix-widget>
|
||||
|
||||
If you have enabled public filters in your meta data attribute configuration, a filter formshows up. To disable, use::
|
||||
|
||||
<pretix-widget event="https://pretix.eu/demo/democon/" disable-filters></pretix-widget>
|
||||
|
||||
pretix Button
|
||||
-------------
|
||||
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
__version__ = "2023.9.0"
|
||||
__version__ = "2023.10.0.dev0"
|
||||
|
||||
@@ -92,6 +92,7 @@ ALL_LANGUAGES = [
|
||||
('id', _('Indonesian')),
|
||||
('it', _('Italian')),
|
||||
('lv', _('Latvian')),
|
||||
('nb-no', _('Norwegian Bokmål')),
|
||||
('pl', _('Polish')),
|
||||
('pt-pt', _('Portuguese (Portugal)')),
|
||||
('pt-br', _('Portuguese (Brazil)')),
|
||||
|
||||
@@ -230,8 +230,8 @@ class EventSerializer(I18nAwareModelSerializer):
|
||||
for key, v in value['meta_data'].items():
|
||||
if key not in self.meta_properties:
|
||||
raise ValidationError(_('Meta data property \'{name}\' does not exist.').format(name=key))
|
||||
if self.meta_properties[key].allowed_values:
|
||||
if v not in [_v.strip() for _v in self.meta_properties[key].allowed_values.splitlines()]:
|
||||
if self.meta_properties[key].choices:
|
||||
if v not in self.meta_properties[key].choice_keys:
|
||||
raise ValidationError(_('Meta data property \'{name}\' does not allow value \'{value}\'.').format(name=key, value=v))
|
||||
return value
|
||||
|
||||
@@ -528,8 +528,8 @@ class SubEventSerializer(I18nAwareModelSerializer):
|
||||
for key, v in value['meta_data'].items():
|
||||
if key not in self.meta_properties:
|
||||
raise ValidationError(_('Meta data property \'{name}\' does not exist.').format(name=key))
|
||||
if self.meta_properties[key].allowed_values:
|
||||
if v not in [_v.strip() for _v in self.meta_properties[key].allowed_values.splitlines()]:
|
||||
if self.meta_properties[key].choices:
|
||||
if v not in self.meta_properties[key].choice_keys:
|
||||
raise ValidationError(_('Meta data property \'{name}\' does not allow value \'{value}\'.').format(name=key, value=v))
|
||||
return value
|
||||
|
||||
@@ -705,6 +705,7 @@ class EventSettingsSerializer(SettingsSerializer):
|
||||
'frontpage_subevent_ordering',
|
||||
'event_list_type',
|
||||
'event_list_available_only',
|
||||
'event_list_filters',
|
||||
'event_calendar_future_only',
|
||||
'frontpage_text',
|
||||
'event_info_text',
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.http import QueryDict
|
||||
from pytz import common_timezones
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from pretix.base.exporter import OrganizerLevelExportMixin
|
||||
from pretix.base.models import ScheduledEventExport, ScheduledOrganizerExport
|
||||
from pretix.base.timeframes import DateFrameField, SerializerDateFrameField
|
||||
|
||||
|
||||
@@ -197,3 +200,92 @@ class JobRunSerializer(serializers.Serializer):
|
||||
raise ValidationError(self.errors)
|
||||
|
||||
return not bool(self._errors)
|
||||
|
||||
|
||||
class ScheduledExportSerializer(serializers.ModelSerializer):
|
||||
schedule_next_run = serializers.DateTimeField(read_only=True)
|
||||
export_identifier = serializers.ChoiceField(choices=[])
|
||||
locale = serializers.ChoiceField(choices=settings.LANGUAGES, default='en')
|
||||
owner = serializers.SlugRelatedField(slug_field='email', read_only=True)
|
||||
error_counter = serializers.IntegerField(read_only=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['export_identifier'].choices = [(e, e) for e in self.context['exporters']]
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get("export_form_data"):
|
||||
identifier = attrs.get('export_identifier', self.instance.export_identifier if self.instance else None)
|
||||
exporter = self.context['exporters'].get(identifier)
|
||||
if exporter:
|
||||
try:
|
||||
JobRunSerializer(exporter=exporter).to_internal_value(attrs["export_form_data"])
|
||||
except ValidationError as e:
|
||||
raise ValidationError({"export_form_data": e.detail})
|
||||
else:
|
||||
raise ValidationError({"export_identifier": ["Unknown exporter."]})
|
||||
return attrs
|
||||
|
||||
def validate_mail_additional_recipients(self, value):
|
||||
d = value.replace(' ', '')
|
||||
if len(d.split(',')) > 25:
|
||||
raise ValidationError('Please enter less than 25 recipients.')
|
||||
return d
|
||||
|
||||
def validate_mail_additional_recipients_cc(self, value):
|
||||
d = value.replace(' ', '')
|
||||
if len(d.split(',')) > 25:
|
||||
raise ValidationError('Please enter less than 25 recipients.')
|
||||
return d
|
||||
|
||||
def validate_mail_additional_recipients_bcc(self, value):
|
||||
d = value.replace(' ', '')
|
||||
if len(d.split(',')) > 25:
|
||||
raise ValidationError('Please enter less than 25 recipients.')
|
||||
return d
|
||||
|
||||
|
||||
class ScheduledEventExportSerializer(ScheduledExportSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ScheduledEventExport
|
||||
fields = [
|
||||
'id',
|
||||
'owner',
|
||||
'export_identifier',
|
||||
'export_form_data',
|
||||
'locale',
|
||||
'mail_additional_recipients',
|
||||
'mail_additional_recipients_cc',
|
||||
'mail_additional_recipients_bcc',
|
||||
'mail_subject',
|
||||
'mail_template',
|
||||
'schedule_rrule',
|
||||
'schedule_rrule_time',
|
||||
'schedule_next_run',
|
||||
'error_counter',
|
||||
]
|
||||
|
||||
|
||||
class ScheduledOrganizerExportSerializer(ScheduledExportSerializer):
|
||||
timezone = serializers.ChoiceField(default=settings.TIME_ZONE, choices=[(a, a) for a in common_timezones])
|
||||
|
||||
class Meta:
|
||||
model = ScheduledOrganizerExport
|
||||
fields = [
|
||||
'id',
|
||||
'owner',
|
||||
'export_identifier',
|
||||
'export_form_data',
|
||||
'locale',
|
||||
'mail_additional_recipients',
|
||||
'mail_additional_recipients_cc',
|
||||
'mail_additional_recipients_bcc',
|
||||
'mail_subject',
|
||||
'mail_template',
|
||||
'schedule_rrule',
|
||||
'schedule_rrule_time',
|
||||
'schedule_next_run',
|
||||
'timezone',
|
||||
'error_counter',
|
||||
]
|
||||
|
||||
@@ -59,7 +59,7 @@ class InlineItemVariationSerializer(I18nAwareModelSerializer):
|
||||
class Meta:
|
||||
model = ItemVariation
|
||||
fields = ('id', 'value', 'active', 'description',
|
||||
'position', 'default_price', 'price', 'original_price', 'require_approval',
|
||||
'position', 'default_price', 'price', 'original_price', 'free_price_suggestion', 'require_approval',
|
||||
'require_membership', 'require_membership_types', 'require_membership_hidden',
|
||||
'checkin_attention', 'available_from', 'available_until',
|
||||
'sales_channels', 'hide_without_voucher', 'meta_data')
|
||||
@@ -83,7 +83,7 @@ class ItemVariationSerializer(I18nAwareModelSerializer):
|
||||
class Meta:
|
||||
model = ItemVariation
|
||||
fields = ('id', 'value', 'active', 'description',
|
||||
'position', 'default_price', 'price', 'original_price', 'require_approval',
|
||||
'position', 'default_price', 'price', 'original_price', 'free_price_suggestion', 'require_approval',
|
||||
'require_membership', 'require_membership_types', 'require_membership_hidden',
|
||||
'checkin_attention', 'available_from', 'available_until',
|
||||
'sales_channels', 'hide_without_voucher', 'meta_data')
|
||||
@@ -234,12 +234,13 @@ class ItemSerializer(I18nAwareModelSerializer):
|
||||
class Meta:
|
||||
model = Item
|
||||
fields = ('id', 'category', 'name', 'internal_name', 'active', 'sales_channels', 'description',
|
||||
'default_price', 'free_price', 'tax_rate', 'tax_rule', 'admission', 'personalized',
|
||||
'position', 'picture', 'available_from', 'available_until',
|
||||
'default_price', 'free_price', 'free_price_suggestion', 'tax_rate', 'tax_rule', 'admission',
|
||||
'personalized', 'position', 'picture', 'available_from', 'available_until',
|
||||
'require_voucher', 'hide_without_voucher', 'allow_cancel', 'require_bundling',
|
||||
'min_per_order', 'max_per_order', 'checkin_attention', 'has_variations', 'variations',
|
||||
'addons', 'bundles', 'original_price', 'require_approval', 'generate_tickets',
|
||||
'show_quota_left', 'hidden_if_available', 'allow_waitinglist', 'issue_giftcard', 'meta_data',
|
||||
'show_quota_left', 'hidden_if_available', 'hidden_if_item_available', 'allow_waitinglist',
|
||||
'issue_giftcard', 'meta_data',
|
||||
'require_membership', 'require_membership_types', 'require_membership_hidden', 'grant_membership_type',
|
||||
'grant_membership_duration_like_event', 'grant_membership_duration_days',
|
||||
'grant_membership_duration_months', 'validity_mode', 'validity_fixed_from', 'validity_fixed_until',
|
||||
|
||||
@@ -501,7 +501,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
# /events/…/checkinlists/…/positions/
|
||||
# We're unable to check this on this level if we're on /checkinrpc/, in which case we rely on the view
|
||||
# layer to not set pdf_data=true in the first place.
|
||||
request and hasattr(request, 'event') and 'can_view_orders' not in request.eventpermset
|
||||
request and hasattr(request, 'eventpermset') and 'can_view_orders' not in request.eventpermset
|
||||
)
|
||||
if ('pdf_data' in self.context and not self.context['pdf_data']) or pdf_data_forbidden:
|
||||
self.fields.pop('pdf_data', None)
|
||||
|
||||
@@ -63,6 +63,7 @@ orga_router.register(r'teams', organizer.TeamViewSet)
|
||||
orga_router.register(r'devices', organizer.DeviceViewSet)
|
||||
orga_router.register(r'orders', order.OrganizerOrderViewSet)
|
||||
orga_router.register(r'invoices', order.InvoiceViewSet)
|
||||
orga_router.register(r'scheduled_exports', exporters.ScheduledOrganizerExportViewSet)
|
||||
orga_router.register(r'exporters', exporters.OrganizerExportersViewSet, basename='exporters')
|
||||
|
||||
team_router = routers.DefaultRouter()
|
||||
@@ -88,6 +89,7 @@ event_router.register(r'taxrules', event.TaxRuleViewSet)
|
||||
event_router.register(r'waitinglistentries', waitinglist.WaitingListViewSet)
|
||||
event_router.register(r'checkinlists', checkin.CheckinListViewSet)
|
||||
event_router.register(r'cartpositions', cart.CartPositionViewSet)
|
||||
event_router.register(r'scheduled_exports', exporters.ScheduledEventExportViewSet)
|
||||
event_router.register(r'exporters', exporters.EventExportersViewSet, basename='exporters')
|
||||
event_router.register(r'shredders', shredders.EventShreddersViewSet, basename='shredders')
|
||||
event_router.register(r'item_meta_properties', event.ItemMetaPropertiesViewSet)
|
||||
|
||||
@@ -89,6 +89,8 @@ class UpdateRequestSerializer(serializers.Serializer):
|
||||
|
||||
class RSAEncryptedField(serializers.Field):
|
||||
def to_representation(self, value):
|
||||
if isinstance(value, memoryview):
|
||||
value = value.tobytes()
|
||||
public_key = load_pem_public_key(
|
||||
self.context['device'].rsa_pubkey.encode(), Backend()
|
||||
)
|
||||
|
||||
@@ -29,14 +29,20 @@ from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from rest_framework import status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
from pretix.api.pagination import TotalOrderingFilter
|
||||
from pretix.api.serializers.exporters import (
|
||||
ExporterSerializer, JobRunSerializer,
|
||||
ExporterSerializer, JobRunSerializer, ScheduledEventExportSerializer,
|
||||
ScheduledOrganizerExportSerializer,
|
||||
)
|
||||
from pretix.base.exporter import OrganizerLevelExportMixin
|
||||
from pretix.base.models import CachedFile, Device, Event, TeamAPIToken
|
||||
from pretix.base.models import (
|
||||
CachedFile, Device, Event, ScheduledEventExport, ScheduledOrganizerExport,
|
||||
TeamAPIToken,
|
||||
)
|
||||
from pretix.base.services.export import export, multiexport
|
||||
from pretix.base.signals import (
|
||||
register_data_exporters, register_multievent_data_exporters,
|
||||
@@ -199,3 +205,152 @@ class OrganizerExportersViewSet(ExportersMixin, viewsets.ViewSet):
|
||||
'provider': instance.identifier,
|
||||
'form_data': data
|
||||
})
|
||||
|
||||
|
||||
class ScheduledExportersViewSet(viewsets.ModelViewSet):
|
||||
filter_backends = (TotalOrderingFilter,)
|
||||
ordering = ('id',)
|
||||
ordering_fields = ('id', 'export_identifier', 'schedule_next_run')
|
||||
|
||||
|
||||
class ScheduledEventExportViewSet(ScheduledExportersViewSet):
|
||||
serializer_class = ScheduledEventExportSerializer
|
||||
queryset = ScheduledEventExport.objects.none()
|
||||
permission = 'can_view_orders'
|
||||
|
||||
def get_queryset(self):
|
||||
perm_holder = self.request.auth if isinstance(self.request.auth, (TeamAPIToken, Device)) else self.request.user
|
||||
if not perm_holder.has_event_permission(self.request.organizer, self.request.event, 'can_change_event_settings',
|
||||
request=self.request):
|
||||
if self.request.user.is_authenticated:
|
||||
qs = self.request.event.scheduled_exports.filter(owner=self.request.user)
|
||||
else:
|
||||
raise PermissionDenied('Scheduled exports require either permission to change event settings or '
|
||||
'user-specific API access.')
|
||||
else:
|
||||
qs = self.request.event.scheduled_exports
|
||||
return qs.select_related("owner")
|
||||
|
||||
def perform_create(self, serializer):
|
||||
if not self.request.user.is_authenticated:
|
||||
raise PermissionDenied('Creation of exports requires user-specific API access.')
|
||||
serializer.save(event=self.request.event, owner=self.request.user)
|
||||
serializer.instance.compute_next_run()
|
||||
serializer.instance.save(update_fields=["schedule_next_run"])
|
||||
self.request.event.log_action(
|
||||
'pretix.event.export.schedule.added',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
ctx['event'] = self.request.event
|
||||
ctx['exporters'] = self.exporters
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def exporters(self):
|
||||
responses = register_data_exporters.send(self.request.event)
|
||||
exporters = [response(self.request.event, self.request.organizer) for r, response in responses if response]
|
||||
return {e.identifier: e for e in exporters}
|
||||
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.compute_next_run()
|
||||
serializer.instance.error_counter = 0
|
||||
serializer.instance.error_last_message = None
|
||||
serializer.instance.save(update_fields=["schedule_next_run", "error_counter", "error_last_message"])
|
||||
self.request.event.log_action(
|
||||
'pretix.event.export.schedule.changed',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
self.request.event.log_action(
|
||||
'pretix.event.export.schedule.deleted',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
)
|
||||
super().perform_destroy(instance)
|
||||
|
||||
|
||||
class ScheduledOrganizerExportViewSet(ScheduledExportersViewSet):
|
||||
serializer_class = ScheduledOrganizerExportSerializer
|
||||
queryset = ScheduledOrganizerExport.objects.none()
|
||||
permission = None
|
||||
|
||||
def get_queryset(self):
|
||||
perm_holder = self.request.auth if isinstance(self.request.auth, (TeamAPIToken, Device)) else self.request.user
|
||||
if not perm_holder.has_organizer_permission(self.request.organizer, 'can_change_organizer_settings',
|
||||
request=self.request):
|
||||
if self.request.user.is_authenticated:
|
||||
qs = self.request.organizer.scheduled_exports.filter(owner=self.request.user)
|
||||
else:
|
||||
raise PermissionDenied('Scheduled exports require either permission to change organizer settings or '
|
||||
'user-specific API access.')
|
||||
else:
|
||||
qs = self.request.organizer.scheduled_exports
|
||||
return qs.select_related("owner")
|
||||
|
||||
def perform_create(self, serializer):
|
||||
if not self.request.user.is_authenticated:
|
||||
raise PermissionDenied('Creation of exports requires user-specific API access.')
|
||||
serializer.save(organizer=self.request.organizer, owner=self.request.user)
|
||||
serializer.instance.compute_next_run()
|
||||
serializer.instance.save(update_fields=["schedule_next_run"])
|
||||
self.request.organizer.log_action(
|
||||
'pretix.organizer.export.schedule.added',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
ctx['organizer'] = self.request.organizer
|
||||
ctx['exporters'] = self.exporters
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def events(self):
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
return self.request.auth.get_events_with_permission('can_view_orders')
|
||||
elif self.request.user.is_authenticated:
|
||||
return self.request.user.get_events_with_permission('can_view_orders', self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def exporters(self):
|
||||
responses = register_multievent_data_exporters.send(self.request.organizer)
|
||||
exporters = [
|
||||
response(Event.objects.none() if issubclass(response, OrganizerLevelExportMixin) else self.events,
|
||||
self.request.organizer)
|
||||
for r, response in responses if response
|
||||
]
|
||||
return {e.identifier: e for e in exporters}
|
||||
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(organizer=self.request.organizer)
|
||||
serializer.instance.compute_next_run()
|
||||
serializer.instance.error_counter = 0
|
||||
serializer.instance.error_last_message = None
|
||||
serializer.instance.save(update_fields=["schedule_next_run", "error_counter", "error_last_message"])
|
||||
self.request.organizer.log_action(
|
||||
'pretix.organizer.export.schedule.changed',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
self.request.organizer.log_action(
|
||||
'pretix.organizer.export.schedule.deleted',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
)
|
||||
super().perform_destroy(instance)
|
||||
|
||||
@@ -103,15 +103,17 @@ def get_all_sales_channels():
|
||||
if _ALL_CHANNELS:
|
||||
return _ALL_CHANNELS
|
||||
|
||||
types = OrderedDict()
|
||||
channels = []
|
||||
for recv, ret in register_sales_channels.send(None):
|
||||
if isinstance(ret, (list, tuple)):
|
||||
for r in ret:
|
||||
types[r.identifier] = r
|
||||
channels += ret
|
||||
else:
|
||||
types[ret.identifier] = ret
|
||||
_ALL_CHANNELS = types
|
||||
return types
|
||||
channels.append(ret)
|
||||
channels.sort(key=lambda c: c.identifier)
|
||||
_ALL_CHANNELS = OrderedDict([(c.identifier, c) for c in channels])
|
||||
if 'web' in _ALL_CHANNELS:
|
||||
_ALL_CHANNELS.move_to_end('web', last=False)
|
||||
return _ALL_CHANNELS
|
||||
|
||||
|
||||
class WebshopSalesChannel(SalesChannel):
|
||||
|
||||
@@ -149,6 +149,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
|
||||
}
|
||||
if self.organizer:
|
||||
htmlctx['organizer'] = self.organizer
|
||||
htmlctx['color'] = self.organizer.settings.primary_color
|
||||
|
||||
if self.event:
|
||||
htmlctx['event'] = self.event
|
||||
|
||||
@@ -1007,20 +1007,20 @@ class PaymentListExporter(ListExporter):
|
||||
if form_data.get('end_date_range'):
|
||||
dt_start, dt_end = resolve_timeframe_to_datetime_start_inclusive_end_exclusive(now(), form_data['end_date_range'], self.timezone)
|
||||
if dt_start:
|
||||
payments = payments.filter(created__gte=dt_start)
|
||||
refunds = refunds .filter(created__gte=dt_start)
|
||||
payments = payments.filter(payment_date__gte=dt_start)
|
||||
refunds = refunds.filter(execution_date__gte=dt_start)
|
||||
if dt_end:
|
||||
payments = payments.filter(created__lt=dt_end)
|
||||
refunds = refunds .filter(created__lt=dt_end)
|
||||
payments = payments.filter(payment_date__lt=dt_end)
|
||||
refunds = refunds.filter(execution_date__lt=dt_end)
|
||||
|
||||
if form_data.get('start_end_date_range'):
|
||||
dt_start, dt_end = resolve_timeframe_to_datetime_start_inclusive_end_exclusive(now(), form_data['start_date_range'], self.timezone)
|
||||
if dt_start:
|
||||
payments = payments.filter(payment_date__gte=dt_start)
|
||||
refunds = refunds .filter(execution_date__gte=dt_start)
|
||||
payments = payments.filter(created__gte=dt_start)
|
||||
refunds = refunds.filter(created__gte=dt_start)
|
||||
if dt_end:
|
||||
payments = payments.filter(payment_date__lt=dt_end)
|
||||
refunds = refunds.filter(execution_date__lt=dt_end)
|
||||
payments = payments.filter(created__lt=dt_end)
|
||||
refunds = refunds.filter(created__lt=dt_end)
|
||||
|
||||
objs = sorted(list(payments) + list(refunds), key=lambda o: o.created)
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 4.2.4 on 2023-10-25 12:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("pretixbase", "0247_checkinlist"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="item",
|
||||
name="free_price_suggestion",
|
||||
field=models.DecimalField(decimal_places=2, max_digits=13, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="itemvariation",
|
||||
name="free_price_suggestion",
|
||||
field=models.DecimalField(decimal_places=2, max_digits=13, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 4.2.4 on 2023-10-30 11:50
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("pretixbase", "0248_item_free_price_suggestion"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="item",
|
||||
name="hidden_if_item_available",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="pretixbase.item",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
# Generated by Django 4.2.4 on 2023-10-31 10:08
|
||||
import i18nfield.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
import pretix.helpers.json
|
||||
|
||||
|
||||
def convert_allowed_values(apps, schema_editor):
|
||||
EventMetaProperty = apps.get_model('pretixbase', 'EventMetaProperty')
|
||||
for emp in EventMetaProperty.objects.filter(allowed_values__isnull=False):
|
||||
emp.choices = [
|
||||
{"key": _v.strip(), "label": {"en": _v.strip()}}
|
||||
for _v in emp.allowed_values.splitlines()
|
||||
]
|
||||
emp.save(update_fields=["choices"])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("pretixbase", "0249_hidden_if_item_available"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="eventmetaproperty",
|
||||
name="filter_public",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="eventmetaproperty",
|
||||
name="public_label",
|
||||
field=i18nfield.fields.I18nCharField(null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="eventmetaproperty",
|
||||
name="position",
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="eventmetaproperty",
|
||||
name="choices",
|
||||
field=models.JSONField(null=True, encoder=pretix.helpers.json.CustomJSONEncoder),
|
||||
),
|
||||
migrations.RunPython(
|
||||
convert_allowed_values,
|
||||
migrations.RunPython.noop
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="eventmetaproperty",
|
||||
name="allowed_values",
|
||||
),
|
||||
]
|
||||
@@ -20,7 +20,6 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import logging
|
||||
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
|
||||
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
#
|
||||
@@ -33,6 +32,7 @@ import logging
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
import logging
|
||||
import os
|
||||
import string
|
||||
import uuid
|
||||
@@ -71,7 +71,7 @@ from pretix.base.validators import EventSlugBanlistValidator
|
||||
from pretix.helpers.database import GroupConcat
|
||||
from pretix.helpers.daterange import daterange
|
||||
from pretix.helpers.hierarkey import clean_filename
|
||||
from pretix.helpers.json import safe_string
|
||||
from pretix.helpers.json import CustomJSONEncoder, safe_string
|
||||
from pretix.helpers.thumb import get_thumbnail
|
||||
|
||||
from ..settings import settings_hierarkey
|
||||
@@ -857,6 +857,10 @@ class Event(EventMixin, LoggedModel):
|
||||
v.item = i
|
||||
v.save(force_insert=True)
|
||||
|
||||
for i in self.items.filter(hidden_if_item_available__isnull=False):
|
||||
i.hidden_if_item_available = item_map[i.hidden_if_item_available_id]
|
||||
i.save()
|
||||
|
||||
for imv in ItemMetaValue.objects.filter(item__event=other):
|
||||
imv.pk = None
|
||||
imv.property = item_meta_properties_map[imv.property_id]
|
||||
@@ -997,6 +1001,7 @@ class Event(EventMixin, LoggedModel):
|
||||
'presale_widget_css_file',
|
||||
'presale_widget_css_checksum',
|
||||
)
|
||||
settings_to_save = []
|
||||
for s in other.settings._objects.all():
|
||||
if s.key in skip_settings:
|
||||
continue
|
||||
@@ -1014,16 +1019,17 @@ class Event(EventMixin, LoggedModel):
|
||||
)
|
||||
newname = default_storage.save(fname, fi)
|
||||
s.value = 'file://' + newname
|
||||
s.save()
|
||||
settings_to_save.append(s)
|
||||
elif s.key == 'tax_rate_default':
|
||||
try:
|
||||
if int(s.value) in tax_map:
|
||||
s.value = tax_map.get(int(s.value)).pk
|
||||
s.save()
|
||||
settings_to_save.append(s)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
s.save()
|
||||
settings_to_save.append(s)
|
||||
other.settings._objects.bulk_create(settings_to_save)
|
||||
|
||||
self.settings.flush()
|
||||
event_copy_data.send(
|
||||
@@ -1641,26 +1647,40 @@ class EventMetaProperty(LoggedModel):
|
||||
help_text=_("If checked, an event can only be taken live if the property is set. In event series, its always "
|
||||
"optional to set a value for individual dates")
|
||||
)
|
||||
allowed_values = models.TextField(
|
||||
choices = models.JSONField(
|
||||
null=True, blank=True,
|
||||
encoder=CustomJSONEncoder,
|
||||
verbose_name=_("Valid values"),
|
||||
help_text=_("If you keep this empty, any value is allowed. Otherwise, enter one possible value per line.")
|
||||
)
|
||||
filter_public = models.BooleanField(
|
||||
default=False, verbose_name=_("Show filter option to customers"),
|
||||
help_text=_("This field will be shown to filter events in the public event list and calendar.")
|
||||
)
|
||||
public_label = I18nCharField(
|
||||
verbose_name=_("Public name"),
|
||||
null=True, blank=True,
|
||||
)
|
||||
filter_allowed = models.BooleanField(
|
||||
default=True, verbose_name=_("Can be used for filtering"),
|
||||
help_text=_("This field will be shown to filter events or reports in the backend, and it can also be used "
|
||||
"for hidden filter parameters in the frontend (e.g. using the widget).")
|
||||
)
|
||||
position = models.IntegerField(
|
||||
default=0
|
||||
)
|
||||
|
||||
def full_clean(self, exclude=None, validate_unique=True):
|
||||
super().full_clean(exclude, validate_unique)
|
||||
if self.default and self.required:
|
||||
raise ValidationError(_("A property can either be required or have a default value, not both."))
|
||||
if self.default and self.allowed_values and self.default not in self.allowed_values.splitlines():
|
||||
raise ValidationError(_("You cannot set a default value that is not a valid value."))
|
||||
|
||||
class Meta:
|
||||
ordering = ("name",)
|
||||
ordering = ("position", "name",)
|
||||
|
||||
@property
|
||||
def choice_keys(self):
|
||||
if self.choices:
|
||||
return [v["key"] for v in self.choices]
|
||||
|
||||
|
||||
class EventMetaValue(LoggedModel):
|
||||
|
||||
@@ -79,7 +79,7 @@ class AbstractScheduledExport(LoggedModel):
|
||||
)
|
||||
|
||||
schedule_rrule = models.TextField(
|
||||
null=True, blank=True, validators=[RRuleValidator()]
|
||||
null=True, blank=True, validators=[RRuleValidator(enforce_simple=True)]
|
||||
)
|
||||
schedule_rrule_time = models.TimeField(
|
||||
verbose_name=_("Requested start time"),
|
||||
|
||||
@@ -431,6 +431,12 @@ class Item(LoggedModel):
|
||||
"additional donations for your event. This is currently not supported for products that are "
|
||||
"bought as an add-on to other products.")
|
||||
)
|
||||
free_price_suggestion = models.DecimalField(
|
||||
verbose_name=_("Suggested price"),
|
||||
help_text=_("This price will be used as the default value of the input field. The user can choose a lower "
|
||||
"value, but not lower than the price this product would have without the free price option."),
|
||||
max_digits=13, decimal_places=2, null=True, blank=True,
|
||||
)
|
||||
tax_rule = models.ForeignKey(
|
||||
'TaxRule',
|
||||
verbose_name=_('Sales tax'),
|
||||
@@ -488,13 +494,24 @@ class Item(LoggedModel):
|
||||
'Quota',
|
||||
null=True, blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("Only show after sellout of"),
|
||||
verbose_name=pgettext_lazy("hidden_if_available_legacy", "Only show after sellout of"),
|
||||
help_text=_("If you select a quota here, this product will only be shown when that quota is "
|
||||
"unavailable. If combined with the option to hide sold-out products, this allows you to "
|
||||
"swap out products for more expensive ones once they are sold out. There might be a short period "
|
||||
"in which both products are visible while all tickets in the referenced quota are reserved, "
|
||||
"but not yet sold.")
|
||||
)
|
||||
hidden_if_item_available = models.ForeignKey(
|
||||
'Item',
|
||||
null=True, blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("Only show after sellout of"),
|
||||
help_text=_("If you select a product here, this product will only be shown when that product is "
|
||||
"sold out. If combined with the option to hide sold-out products, this allows you to "
|
||||
"swap out products for more expensive ones once the cheaper option is sold out. There might "
|
||||
"be a short period in which both products are visible while all tickets of the referenced "
|
||||
"product are reserved, but not yet sold.")
|
||||
)
|
||||
require_voucher = models.BooleanField(
|
||||
verbose_name=_('This product can only be bought using a voucher.'),
|
||||
default=False,
|
||||
@@ -1021,6 +1038,12 @@ class ItemVariation(models.Model):
|
||||
help_text=_('If set, this will be displayed next to the current price to show that the current price is a '
|
||||
'discounted one. This is just a cosmetic setting and will not actually impact pricing.')
|
||||
)
|
||||
free_price_suggestion = models.DecimalField(
|
||||
verbose_name=_("Suggested price"),
|
||||
help_text=_("This price will be used as the default value of the input field. The user can choose a lower "
|
||||
"value, but not lower than the price this product would have without the free price option."),
|
||||
max_digits=13, decimal_places=2, null=True, blank=True,
|
||||
)
|
||||
require_approval = models.BooleanField(
|
||||
verbose_name=_('Require approval'),
|
||||
default=False,
|
||||
|
||||
@@ -1271,6 +1271,21 @@ class QuestionAnswer(models.Model):
|
||||
return self.file.name.split('.', 1)[-1]
|
||||
|
||||
def __str__(self):
|
||||
return self.to_string(use_cached=True)
|
||||
|
||||
def to_string_i18n(self):
|
||||
return self.to_string(use_cached=False)
|
||||
|
||||
def to_string(self, use_cached=True):
|
||||
"""
|
||||
Render this answer as a string.
|
||||
|
||||
:param use_cached: If ``True`` (default), choice and multiple choice questions will show their cached
|
||||
value, i.e. the value of the selected options at the time of saving and in the language
|
||||
the answer was saved in. If ``False``, the values will instead be loaded from the
|
||||
database, yielding current and translated values of the options. However, additional database
|
||||
queries might be required.
|
||||
"""
|
||||
if self.question.type == Question.TYPE_BOOLEAN and self.answer == "True":
|
||||
return str(_("Yes"))
|
||||
elif self.question.type == Question.TYPE_BOOLEAN and self.answer == "False":
|
||||
@@ -1305,6 +1320,8 @@ class QuestionAnswer(models.Model):
|
||||
return PhoneNumber.from_string(self.answer).as_international
|
||||
except NumberParseException:
|
||||
return self.answer
|
||||
elif self.question.type in (Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE) and self.answer and not use_cached:
|
||||
return ", ".join(str(o.answer) for o in self.options.all())
|
||||
else:
|
||||
return self.answer
|
||||
|
||||
|
||||
@@ -817,7 +817,7 @@ class BasePaymentProvider:
|
||||
"""
|
||||
return ""
|
||||
|
||||
def order_change_allowed(self, order: Order) -> bool:
|
||||
def order_change_allowed(self, order: Order, request: HttpRequest=None) -> bool:
|
||||
"""
|
||||
Will be called to check whether it is allowed to change the payment method of
|
||||
an order to this one.
|
||||
@@ -835,7 +835,12 @@ class BasePaymentProvider:
|
||||
return False
|
||||
|
||||
if self.settings.get('_hidden', as_type=bool):
|
||||
return False
|
||||
if request:
|
||||
hashes = set(request.session.get('pretix_unlock_hashes', [])) | set(order.meta_info_data.get('unlock_hashes', []))
|
||||
if hashlib.sha256((self.settings._hidden_seed + self.event.slug).encode()).hexdigest() not in hashes:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
restricted_countries = self.settings.get('_restricted_countries', as_type=list)
|
||||
if restricted_countries:
|
||||
|
||||
@@ -567,7 +567,7 @@ def variables_from_questions(sender, *args, **kwargs):
|
||||
if not a:
|
||||
return ""
|
||||
else:
|
||||
return str(a)
|
||||
return a.to_string_i18n()
|
||||
|
||||
d = {}
|
||||
for q in sender.questions.all():
|
||||
|
||||
+82
-36
@@ -39,7 +39,7 @@ BASE_CHOICES = (
|
||||
('presale_end', _('Presale end')),
|
||||
)
|
||||
|
||||
RelativeDate = namedtuple('RelativeDate', ['days_before', 'minutes_before', 'time', 'base_date_name'])
|
||||
RelativeDate = namedtuple('RelativeDate', ['days', 'minutes', 'time', 'is_after', 'base_date_name'], defaults=(0, None, None, False, 'date_from'))
|
||||
|
||||
|
||||
class RelativeDateWrapper:
|
||||
@@ -64,7 +64,7 @@ class RelativeDateWrapper:
|
||||
elif isinstance(self.data, datetime.date):
|
||||
return self.data
|
||||
else:
|
||||
if self.data.minutes_before is not None:
|
||||
if self.data.minutes is not None:
|
||||
raise ValueError('A minute-based relative datetime can not be used as a date')
|
||||
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
@@ -77,7 +77,10 @@ class RelativeDateWrapper:
|
||||
else:
|
||||
base_date = getattr(event, self.data.base_date_name) or event.date_from
|
||||
|
||||
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.data.days_before)
|
||||
if self.data.is_after:
|
||||
new_date = base_date.astimezone(tz) + datetime.timedelta(days=self.data.days)
|
||||
else:
|
||||
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.data.days)
|
||||
return new_date.date()
|
||||
|
||||
def datetime(self, event) -> datetime.datetime:
|
||||
@@ -96,10 +99,16 @@ class RelativeDateWrapper:
|
||||
else:
|
||||
base_date = getattr(event, self.data.base_date_name) or event.date_from
|
||||
|
||||
if self.data.minutes_before is not None:
|
||||
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.data.minutes_before)
|
||||
if self.data.minutes is not None:
|
||||
if self.data.is_after:
|
||||
return base_date.astimezone(tz) + datetime.timedelta(minutes=self.data.minutes)
|
||||
else:
|
||||
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.data.minutes)
|
||||
else:
|
||||
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.data.days_before)).astimezone(tz)
|
||||
if self.data.is_after:
|
||||
new_date = (base_date.astimezone(tz) + datetime.timedelta(days=self.data.days)).astimezone(tz)
|
||||
else:
|
||||
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.data.days)).astimezone(tz)
|
||||
if self.data.time:
|
||||
new_date = new_date.replace(
|
||||
hour=self.data.time.hour,
|
||||
@@ -113,15 +122,17 @@ class RelativeDateWrapper:
|
||||
if isinstance(self.data, (datetime.datetime, datetime.date)):
|
||||
return self.data.isoformat()
|
||||
else:
|
||||
if self.data.minutes_before is not None:
|
||||
return 'RELDATE/minutes/{}/{}/'.format( #
|
||||
self.data.minutes_before,
|
||||
self.data.base_date_name
|
||||
if self.data.minutes is not None:
|
||||
return 'RELDATE/minutes/{}/{}/{}'.format( #
|
||||
self.data.minutes,
|
||||
self.data.base_date_name,
|
||||
'after' if self.data.is_after else '',
|
||||
)
|
||||
return 'RELDATE/{}/{}/{}/'.format( #
|
||||
self.data.days_before,
|
||||
return 'RELDATE/{}/{}/{}/{}'.format( #
|
||||
self.data.days,
|
||||
self.data.time.strftime('%H:%M:%S') if self.data.time else '-',
|
||||
self.data.base_date_name
|
||||
self.data.base_date_name,
|
||||
'after' if self.data.is_after else '',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -130,10 +141,11 @@ class RelativeDateWrapper:
|
||||
parts = input.split('/')
|
||||
if parts[1] == 'minutes':
|
||||
data = RelativeDate(
|
||||
days_before=0,
|
||||
minutes_before=int(parts[2]),
|
||||
days=0,
|
||||
minutes=int(parts[2]),
|
||||
base_date_name=parts[3],
|
||||
time=None
|
||||
time=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
else:
|
||||
if parts[2] == '-':
|
||||
@@ -143,17 +155,19 @@ class RelativeDateWrapper:
|
||||
time = datetime.time(hour=int(timeparts[0]), minute=int(timeparts[1]), second=int(timeparts[2]))
|
||||
try:
|
||||
data = RelativeDate(
|
||||
days_before=int(parts[1] or 0),
|
||||
days=int(parts[1] or 0),
|
||||
base_date_name=parts[3],
|
||||
time=time,
|
||||
minutes_before=None
|
||||
minutes=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
except ValueError:
|
||||
data = RelativeDate(
|
||||
days_before=0,
|
||||
days=0,
|
||||
base_date_name=parts[3],
|
||||
time=time,
|
||||
minutes_before=None
|
||||
minutes=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
if data.base_date_name not in [k[0] for k in BASE_CHOICES]:
|
||||
raise ValueError('{} is not a valid base date'.format(data.base_date_name))
|
||||
@@ -165,20 +179,30 @@ class RelativeDateWrapper:
|
||||
return len(self.to_string())
|
||||
|
||||
|
||||
BEFORE_AFTER_CHOICE = (
|
||||
('before', _('before')),
|
||||
('after', _('after')),
|
||||
)
|
||||
|
||||
|
||||
class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
template_name = 'pretixbase/forms/widgets/reldatetime.html'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.status_choices = kwargs.pop('status_choices')
|
||||
base_choices = kwargs.pop('base_choices')
|
||||
widgets = (
|
||||
forms.RadioSelect(choices=self.status_choices),
|
||||
forms.DateTimeInput(
|
||||
attrs={'class': 'datetimepicker'}
|
||||
),
|
||||
forms.NumberInput(),
|
||||
forms.Select(choices=kwargs.pop('base_choices')),
|
||||
forms.Select(choices=base_choices),
|
||||
forms.TimeInput(attrs={'placeholder': _('Time'), 'class': 'timepickerfield'}),
|
||||
forms.NumberInput(),
|
||||
forms.Select(choices=base_choices),
|
||||
forms.Select(choices=BEFORE_AFTER_CHOICE),
|
||||
forms.Select(choices=BEFORE_AFTER_CHOICE),
|
||||
)
|
||||
super().__init__(widgets=widgets, *args, **kwargs)
|
||||
|
||||
@@ -186,12 +210,14 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
if isinstance(value, str):
|
||||
value = RelativeDateWrapper.from_string(value)
|
||||
if not value:
|
||||
return ['unset', None, 1, 'date_from', None, 0]
|
||||
return ['unset', None, 1, 'date_from', None, 0, "date_from", "before", "before"]
|
||||
elif isinstance(value.data, (datetime.datetime, datetime.date)):
|
||||
return ['absolute', value.data, 1, 'date_from', None, 0]
|
||||
elif value.data.minutes_before is not None:
|
||||
return ['relative_minutes', None, None, value.data.base_date_name, None, value.data.minutes_before]
|
||||
return ['relative', None, value.data.days_before, value.data.base_date_name, value.data.time, 0]
|
||||
return ['absolute', value.data, 1, 'date_from', None, 0, "date_from", "before", "before"]
|
||||
elif value.data.minutes is not None:
|
||||
return ['relative_minutes', None, None, value.data.base_date_name, None, value.data.minutes, value.data.base_date_name,
|
||||
"after" if value.data.is_after else "before", "after" if value.data.is_after else "before"]
|
||||
return ['relative', None, value.data.days, value.data.base_date_name, value.data.time, 0, value.data.base_date_name,
|
||||
"after" if value.data.is_after else "before", "after" if value.data.is_after else "before"]
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
ctx = super().get_context(name, value, attrs)
|
||||
@@ -234,6 +260,18 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
forms.IntegerField(
|
||||
required=False
|
||||
),
|
||||
forms.ChoiceField(
|
||||
choices=choices,
|
||||
required=False
|
||||
),
|
||||
forms.ChoiceField(
|
||||
choices=BEFORE_AFTER_CHOICE,
|
||||
required=False
|
||||
),
|
||||
forms.ChoiceField(
|
||||
choices=BEFORE_AFTER_CHOICE,
|
||||
required=False
|
||||
),
|
||||
)
|
||||
if 'widget' not in kwargs:
|
||||
kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=choices)
|
||||
@@ -257,17 +295,19 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
return None
|
||||
elif data_list[0] == 'relative_minutes':
|
||||
return RelativeDateWrapper(RelativeDate(
|
||||
days_before=0,
|
||||
days=0,
|
||||
base_date_name=data_list[3],
|
||||
time=None,
|
||||
minutes_before=data_list[5]
|
||||
minutes=data_list[5],
|
||||
is_after=data_list[7] == "after",
|
||||
))
|
||||
else:
|
||||
return RelativeDateWrapper(RelativeDate(
|
||||
days_before=data_list[2],
|
||||
base_date_name=data_list[3],
|
||||
days=data_list[2],
|
||||
base_date_name=data_list[6],
|
||||
time=data_list[4],
|
||||
minutes_before=None
|
||||
minutes=None,
|
||||
is_after=data_list[8] == "after",
|
||||
))
|
||||
|
||||
def has_changed(self, initial, data):
|
||||
@@ -298,6 +338,7 @@ class RelativeDateWidget(RelativeDateTimeWidget):
|
||||
),
|
||||
forms.NumberInput(),
|
||||
forms.Select(choices=kwargs.pop('base_choices')),
|
||||
forms.Select(choices=BEFORE_AFTER_CHOICE),
|
||||
)
|
||||
forms.MultiWidget.__init__(self, widgets=widgets, *args, **kwargs)
|
||||
|
||||
@@ -305,10 +346,10 @@ class RelativeDateWidget(RelativeDateTimeWidget):
|
||||
if isinstance(value, str):
|
||||
value = RelativeDateWrapper.from_string(value)
|
||||
if not value:
|
||||
return ['unset', None, 1, 'date_from']
|
||||
return ['unset', None, 1, 'date_from', 'before']
|
||||
elif isinstance(value.data, (datetime.datetime, datetime.date)):
|
||||
return ['absolute', value.data, 1, 'date_from']
|
||||
return ['relative', None, value.data.days_before, value.data.base_date_name]
|
||||
return ['absolute', value.data, 1, 'date_from', 'before']
|
||||
return ['relative', None, value.data.days, value.data.base_date_name, "after" if value.data.is_after else "before"]
|
||||
|
||||
|
||||
class RelativeDateField(RelativeDateTimeField):
|
||||
@@ -335,6 +376,10 @@ class RelativeDateField(RelativeDateTimeField):
|
||||
choices=BASE_CHOICES,
|
||||
required=False
|
||||
),
|
||||
forms.ChoiceField(
|
||||
choices=BEFORE_AFTER_CHOICE,
|
||||
required=False
|
||||
),
|
||||
)
|
||||
if 'widget' not in kwargs:
|
||||
kwargs['widget'] = RelativeDateWidget(status_choices=status_choices, base_choices=BASE_CHOICES)
|
||||
@@ -351,9 +396,10 @@ class RelativeDateField(RelativeDateTimeField):
|
||||
return None
|
||||
else:
|
||||
return RelativeDateWrapper(RelativeDate(
|
||||
days_before=data_list[2],
|
||||
days=data_list[2],
|
||||
base_date_name=data_list[3],
|
||||
time=None, minutes_before=None
|
||||
time=None, minutes=None,
|
||||
is_after=data_list[4] == "after"
|
||||
))
|
||||
|
||||
def clean(self, value):
|
||||
|
||||
@@ -199,7 +199,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
||||
positions = list(
|
||||
invoice.order.positions.select_related('addon_to', 'item', 'tax_rule', 'subevent', 'variation').annotate(
|
||||
addon_c=Count('addons')
|
||||
).prefetch_related('answers', 'answers__question').order_by('positionid', 'id')
|
||||
).prefetch_related('answers', 'answers__options', 'answers__question').order_by('positionid', 'id')
|
||||
)
|
||||
|
||||
reverse_charge = False
|
||||
@@ -247,7 +247,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
||||
desc += "<br />{}{} {}".format(
|
||||
answ.question.question,
|
||||
"" if str(answ.question.question).endswith("?") else ":",
|
||||
str(answ)
|
||||
answ.to_string_i18n()
|
||||
)
|
||||
|
||||
if invoice.event.has_subevents:
|
||||
|
||||
@@ -1380,7 +1380,9 @@ def send_download_reminders(sender, **kwargs):
|
||||
download_reminder_sent=False,
|
||||
datetime__lte=now() - timedelta(hours=2),
|
||||
first_date__gte=today,
|
||||
).only('pk', 'event_id', 'sales_channel').order_by('event_id')
|
||||
).only(
|
||||
'pk', 'event_id', 'sales_channel', 'datetime',
|
||||
).order_by('event_id')
|
||||
event_id = None
|
||||
days = None
|
||||
event = None
|
||||
|
||||
@@ -80,7 +80,7 @@ def assign_automatically(event: Event, user_id: int=None, subevent_id: int=None)
|
||||
voucher__isnull=True
|
||||
).select_related('item', 'variation', 'subevent').prefetch_related(
|
||||
'item__quotas', 'variation__quotas'
|
||||
).order_by('-priority', 'created')
|
||||
).order_by('-priority', 'created', 'pk')
|
||||
|
||||
if subevent_id and event.has_subevents:
|
||||
subevent = event.subevents.get(id=subevent_id)
|
||||
|
||||
@@ -1606,6 +1606,16 @@ DEFAULTS = {
|
||||
help_text=_('If your event series has more than 50 dates in the future, only the month or week calendar can be used.')
|
||||
),
|
||||
},
|
||||
'event_list_filters': {
|
||||
'default': 'True',
|
||||
'type': bool,
|
||||
'form_class': forms.BooleanField,
|
||||
'serializer_class': serializers.BooleanField,
|
||||
'form_kwargs': dict(
|
||||
label=_("Show filter options for calendar or list view"),
|
||||
help_text=_("You can set up possible filters as meta properties in your organizer settings.")
|
||||
)
|
||||
},
|
||||
'event_list_available_only': {
|
||||
'default': 'False',
|
||||
'type': bool,
|
||||
@@ -1677,6 +1687,8 @@ DEFAULTS = {
|
||||
('gte', _('Only allow changes if the resulting price is higher or equal than the previous price.')),
|
||||
('gt', _('Only allow changes if the resulting price is higher than the previous price.')),
|
||||
('eq', _('Only allow changes if the resulting price is equal to the previous price.')),
|
||||
('gte_paid', _('Allow changes regardless of price, as long as no refund is required (i.e. the resulting '
|
||||
'price is not lower than what has already been paid).')),
|
||||
('any', _('Allow changes regardless of price, even if this results in a refund.')),
|
||||
)
|
||||
),
|
||||
@@ -1686,6 +1698,8 @@ DEFAULTS = {
|
||||
('gte', _('Only allow changes if the resulting price is higher or equal than the previous price.')),
|
||||
('gt', _('Only allow changes if the resulting price is higher than the previous price.')),
|
||||
('eq', _('Only allow changes if the resulting price is equal to the previous price.')),
|
||||
('gte_paid', _('Allow changes regardless of price, as long as no refund is required (i.e. the resulting '
|
||||
'price is not lower than what has already been paid).')),
|
||||
('any', _('Allow changes regardless of price, even if this results in a refund.')),
|
||||
),
|
||||
widget=forms.RadioSelect,
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
{% include widget.subwidgets.1.template_name with widget=widget.subwidgets.1 %}
|
||||
{% elif selopt.value == "relative" %}
|
||||
{% include widget.subwidgets.2.template_name with widget=widget.subwidgets.2 %}
|
||||
{% trans "days before" %}
|
||||
{% trans "days" %}
|
||||
{% include widget.subwidgets.4.template_name with widget=widget.subwidgets.4 %}
|
||||
{% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
{% include widget.subwidgets.1.template_name with widget=widget.subwidgets.1 %}
|
||||
{% elif selopt.value == "relative_minutes" %}
|
||||
{% include widget.subwidgets.5.template_name with widget=widget.subwidgets.5 %}
|
||||
{% trans "minutes before" %}
|
||||
{% trans "minutes" %}
|
||||
{% include widget.subwidgets.7.template_name with widget=widget.subwidgets.7 %}
|
||||
{% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %}
|
||||
{% elif selopt.value == "relative" %}
|
||||
{% include widget.subwidgets.2.template_name with widget=widget.subwidgets.2 %}
|
||||
{% trans "days before" %}
|
||||
{% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %}
|
||||
{% trans "days" %}
|
||||
{% include widget.subwidgets.8.template_name with widget=widget.subwidgets.8 %}
|
||||
{% include widget.subwidgets.6.template_name with widget=widget.subwidgets.6 %}
|
||||
{% trans "at" %}
|
||||
{% include widget.subwidgets.4.template_name with widget=widget.subwidgets.4 %}
|
||||
{% endif %}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#
|
||||
from decimal import ROUND_HALF_UP, Decimal
|
||||
|
||||
from babel import Locale, UnknownLocaleError
|
||||
from babel.numbers import format_currency
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
@@ -47,25 +48,29 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
|
||||
places = settings.CURRENCY_PLACES.get(arg, 2)
|
||||
rounded = value.quantize(Decimal('1') / 10 ** places, ROUND_HALF_UP)
|
||||
if places < 2 and rounded != value:
|
||||
places = 2
|
||||
# We display decimal places even if we shouldn't for this currency if rounding
|
||||
# would make the numbers incorrect. If this branch executes, it's likely a bug in
|
||||
# pretix, but we won't show wrong numbers!
|
||||
if hide_currency:
|
||||
return floatformat(value, 2)
|
||||
else:
|
||||
return '{} {}'.format(arg, floatformat(value, 2))
|
||||
|
||||
if hide_currency:
|
||||
return floatformat(value, places)
|
||||
|
||||
locale_parts = translation.get_language().split("-", 1)
|
||||
locale = locale_parts[0]
|
||||
if len(locale_parts) > 1 and len(locale_parts[1]) == 2:
|
||||
try:
|
||||
locale = Locale(locale_parts[0], locale_parts[1].upper())
|
||||
except UnknownLocaleError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if rounded != value:
|
||||
# We display decimal places even if we shouldn't for this currency if rounding
|
||||
# would make the numbers incorrect. If this branch executes, it's likely a bug in
|
||||
# pretix, but we won't show wrong numbers!
|
||||
return '{} {}'.format(
|
||||
arg,
|
||||
floatformat(value, 2)
|
||||
)
|
||||
return format_currency(value, arg, locale=translation.get_language()[:2])
|
||||
return format_currency(value, arg, locale=locale)
|
||||
except:
|
||||
return '{} {}'.format(
|
||||
arg,
|
||||
floatformat(value, places)
|
||||
)
|
||||
return '{} {}'.format(arg, floatformat(value, places))
|
||||
|
||||
|
||||
@register.filter("money_numberfield")
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from dateutil.rrule import rrulestr
|
||||
import calendar
|
||||
|
||||
from dateutil.rrule import DAILY, MONTHLY, WEEKLY, YEARLY, rrule, rrulestr
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import validate_email
|
||||
@@ -40,7 +42,6 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class BanlistValidator:
|
||||
|
||||
banlist = []
|
||||
|
||||
def __call__(self, value):
|
||||
@@ -55,7 +56,6 @@ class BanlistValidator:
|
||||
|
||||
@deconstructible
|
||||
class EventSlugBanlistValidator(BanlistValidator):
|
||||
|
||||
banlist = [
|
||||
'download',
|
||||
'healthcheck',
|
||||
@@ -77,7 +77,6 @@ class EventSlugBanlistValidator(BanlistValidator):
|
||||
|
||||
@deconstructible
|
||||
class OrganizerSlugBanlistValidator(BanlistValidator):
|
||||
|
||||
banlist = [
|
||||
'download',
|
||||
'healthcheck',
|
||||
@@ -98,7 +97,6 @@ class OrganizerSlugBanlistValidator(BanlistValidator):
|
||||
|
||||
@deconstructible
|
||||
class EmailBanlistValidator(BanlistValidator):
|
||||
|
||||
banlist = [
|
||||
settings.PRETIX_EMAIL_NONE_VALUE,
|
||||
]
|
||||
@@ -112,8 +110,45 @@ def multimail_validate(val):
|
||||
|
||||
|
||||
class RRuleValidator:
|
||||
def __init__(self, enforce_simple=False):
|
||||
self.enforce_simple = enforce_simple
|
||||
|
||||
def __call__(self, value):
|
||||
try:
|
||||
rrulestr(value)
|
||||
parsed = rrulestr(value)
|
||||
except Exception:
|
||||
raise ValidationError("Not a valid rrule.")
|
||||
|
||||
if self.enforce_simple:
|
||||
# Validate that only things are used that we can represent in our UI for later editing
|
||||
|
||||
if not isinstance(parsed, rrule):
|
||||
raise ValidationError("Only a single RRULE is allowed, no combination of rules.")
|
||||
|
||||
if parsed._freq not in (YEARLY, MONTHLY, WEEKLY, DAILY):
|
||||
raise ValidationError("Unsupported FREQ value")
|
||||
if parsed._wkst != calendar.firstweekday():
|
||||
raise ValidationError("Unsupported WKST value")
|
||||
if parsed._bysetpos:
|
||||
if len(parsed._bysetpos) > 1:
|
||||
raise ValidationError("Only one BYSETPOS value allowed")
|
||||
if parsed._freq == YEARLY and parsed._bysetpos not in (1, 2, 3, -1):
|
||||
raise ValidationError("BYSETPOS value not allowed, should be 1, 2, 3 or -1")
|
||||
elif parsed._freq == MONTHLY and parsed._bysetpos not in (1, 2, 3, -1):
|
||||
raise ValidationError("BYSETPOS value not allowed, should be 1, 2, 3 or -1")
|
||||
elif parsed._freq not in (YEARLY, MONTHLY):
|
||||
raise ValidationError("BYSETPOS not allowed for this FREQ")
|
||||
if parsed._bymonthday:
|
||||
raise ValidationError("BYMONTHDAY not supported")
|
||||
if parsed._byyearday:
|
||||
raise ValidationError("BYYEARDAY not supported")
|
||||
if parsed._byeaster:
|
||||
raise ValidationError("BYEASTER not supported")
|
||||
if parsed._byweekno:
|
||||
raise ValidationError("BYWEEKNO not supported")
|
||||
if len(parsed._byhour) > 1 or set(parsed._byhour) != {parsed._dtstart.hour}:
|
||||
raise ValidationError("BYHOUR not supported")
|
||||
if len(parsed._byminute) > 1 or set(parsed._byminute) != {parsed._dtstart.minute}:
|
||||
raise ValidationError("BYMINUTE not supported")
|
||||
if len(parsed._bysecond) > 1 or set(parsed._bysecond) != {parsed._dtstart.second}:
|
||||
raise ValidationError("BYSECOND not supported")
|
||||
|
||||
@@ -208,7 +208,7 @@ class EventWizardBasicsForm(I18nModelForm):
|
||||
del self.fields['team']
|
||||
else:
|
||||
self.fields['team'].queryset = self.user.teams.filter(organizer=self.organizer)
|
||||
if not self.organizer.settings.get("event_team_provisioning", True, as_type=bool):
|
||||
if self.organizer.pk and not self.organizer.settings.get("event_team_provisioning", True, as_type=bool):
|
||||
self.fields['team'].required = True
|
||||
self.fields['team'].empty_label = None
|
||||
self.fields['team'].initial = 0
|
||||
@@ -316,12 +316,12 @@ class EventMetaValueForm(forms.ModelForm):
|
||||
self.property = kwargs.pop('property')
|
||||
self.disabled = kwargs.pop('disabled')
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.property.allowed_values:
|
||||
if self.property.choices:
|
||||
self.fields['value'] = forms.ChoiceField(
|
||||
label=self.property.name,
|
||||
choices=[
|
||||
('', _('Default ({value})').format(value=self.property.default) if self.property.default else ''),
|
||||
] + [(a.strip(), a.strip()) for a in self.property.allowed_values.splitlines()],
|
||||
] + [(a.strip(), a.strip()) for a in self.property.choice_keys],
|
||||
)
|
||||
else:
|
||||
self.fields['value'].label = self.property.name
|
||||
@@ -558,6 +558,7 @@ class EventSettingsForm(EventSettingsValidationMixin, SettingsForm):
|
||||
'low_availability_percentage',
|
||||
'event_list_type',
|
||||
'event_list_available_only',
|
||||
'event_list_filters',
|
||||
'event_calendar_future_only',
|
||||
'frontpage_text',
|
||||
'event_info_text',
|
||||
@@ -645,6 +646,7 @@ class EventSettingsForm(EventSettingsValidationMixin, SettingsForm):
|
||||
del self.fields['frontpage_subevent_ordering']
|
||||
del self.fields['event_list_type']
|
||||
del self.fields['event_list_available_only']
|
||||
del self.fields['event_list_filters']
|
||||
del self.fields['event_calendar_future_only']
|
||||
|
||||
# create "virtual" fields for better UX when editing <name>_asked and <name>_required fields
|
||||
|
||||
@@ -1599,6 +1599,20 @@ class EventFilterForm(FilterForm):
|
||||
}),
|
||||
required=False
|
||||
)
|
||||
date_from = forms.DateField(
|
||||
label=_('Date from'),
|
||||
required=False,
|
||||
widget=DatePickerWidget({
|
||||
'placeholder': _('Date from'),
|
||||
}),
|
||||
)
|
||||
date_until = forms.DateField(
|
||||
label=_('Date until'),
|
||||
required=False,
|
||||
widget=DatePickerWidget({
|
||||
'placeholder': _('Date until'),
|
||||
}),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.request = kwargs.pop('request')
|
||||
@@ -1680,6 +1694,22 @@ class EventFilterForm(FilterForm):
|
||||
Q(name__icontains=i18ncomp(query)) | Q(slug__icontains=query)
|
||||
)
|
||||
|
||||
if fdata.get('date_until'):
|
||||
date_end = make_aware(datetime.combine(
|
||||
fdata.get('date_until') + timedelta(days=1),
|
||||
time(hour=0, minute=0, second=0, microsecond=0)
|
||||
), get_current_timezone())
|
||||
qs = qs.filter(
|
||||
Q(date_to__isnull=True, date_from__lt=date_end) |
|
||||
Q(date_to__isnull=False, date_to__lt=date_end)
|
||||
)
|
||||
if fdata.get('date_from'):
|
||||
date_start = make_aware(datetime.combine(
|
||||
fdata.get('date_from'),
|
||||
time(hour=0, minute=0, second=0, microsecond=0)
|
||||
), get_current_timezone())
|
||||
qs = qs.filter(date_from__gte=date_start)
|
||||
|
||||
filters_by_property_name = {}
|
||||
for i, p in enumerate(self.meta_properties):
|
||||
d = fdata.get('meta_{}'.format(p.name))
|
||||
|
||||
@@ -45,7 +45,7 @@ from django.db.models import Max
|
||||
from django.forms.formsets import DELETION_FIELD_NAME
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import escape
|
||||
from django.utils.html import escape, format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import (
|
||||
gettext as __, gettext_lazy as _, pgettext_lazy,
|
||||
@@ -387,6 +387,7 @@ class ItemCreateForm(I18nModelForm):
|
||||
'allow_waitinglist',
|
||||
'show_quota_left',
|
||||
'hidden_if_available',
|
||||
'hidden_if_item_available',
|
||||
'require_bundling',
|
||||
'require_membership',
|
||||
'grant_membership_type',
|
||||
@@ -550,19 +551,43 @@ class ItemUpdateForm(I18nModelForm):
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
change_decimal_field(self.fields['default_price'], self.event.currency)
|
||||
self.fields['hidden_if_available'].queryset = self.event.quotas.all()
|
||||
self.fields['hidden_if_available'].widget = Select2(
|
||||
|
||||
if self.instance.hidden_if_available_id:
|
||||
self.fields['hidden_if_available'].queryset = self.event.quotas.all()
|
||||
self.fields['hidden_if_available'].help_text = format_html(
|
||||
"<strong>{}</strong> {}",
|
||||
_("This option is deprecated. For new products, use the newer option below that refers to another "
|
||||
"product instead of a quota."),
|
||||
self.fields['hidden_if_available'].help_text
|
||||
)
|
||||
self.fields['hidden_if_available'].widget = Select2(
|
||||
attrs={
|
||||
'data-model-select2': 'generic',
|
||||
'data-select2-url': reverse('control:event.items.quotas.select2', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
}),
|
||||
'data-placeholder': _('Shown independently of other products')
|
||||
}
|
||||
)
|
||||
self.fields['hidden_if_available'].widget.choices = self.fields['hidden_if_available'].choices
|
||||
self.fields['hidden_if_available'].required = False
|
||||
else:
|
||||
del self.fields['hidden_if_available']
|
||||
|
||||
self.fields['hidden_if_item_available'].queryset = self.event.items.exclude(id=self.instance.id)
|
||||
self.fields['hidden_if_item_available'].widget = Select2(
|
||||
attrs={
|
||||
'data-model-select2': 'generic',
|
||||
'data-select2-url': reverse('control:event.items.quotas.select2', kwargs={
|
||||
'data-select2-url': reverse('control:event.items.select2', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
}),
|
||||
'data-placeholder': _('Shown independently of other products')
|
||||
}
|
||||
)
|
||||
self.fields['hidden_if_available'].widget.choices = self.fields['hidden_if_available'].choices
|
||||
self.fields['hidden_if_available'].required = False
|
||||
self.fields['hidden_if_item_available'].widget.choices = self.fields['hidden_if_item_available'].choices
|
||||
self.fields['hidden_if_item_available'].required = False
|
||||
|
||||
self.fields['category'].queryset = self.instance.event.categories.all()
|
||||
self.fields['category'].widget = Select2(
|
||||
@@ -577,6 +602,8 @@ class ItemUpdateForm(I18nModelForm):
|
||||
)
|
||||
self.fields['category'].widget.choices = self.fields['category'].choices
|
||||
|
||||
self.fields['free_price_suggestion'].widget.attrs['data-display-dependency'] = '#id_free_price'
|
||||
|
||||
qs = self.event.organizer.membership_types.all()
|
||||
if qs:
|
||||
self.fields['require_membership_types'].queryset = qs
|
||||
@@ -664,6 +691,7 @@ class ItemUpdateForm(I18nModelForm):
|
||||
'picture',
|
||||
'default_price',
|
||||
'free_price',
|
||||
'free_price_suggestion',
|
||||
'tax_rule',
|
||||
'available_from',
|
||||
'available_until',
|
||||
@@ -680,6 +708,7 @@ class ItemUpdateForm(I18nModelForm):
|
||||
'require_bundling',
|
||||
'show_quota_left',
|
||||
'hidden_if_available',
|
||||
'hidden_if_item_available',
|
||||
'issue_giftcard',
|
||||
'require_membership',
|
||||
'require_membership_types',
|
||||
@@ -706,6 +735,7 @@ class ItemUpdateForm(I18nModelForm):
|
||||
'validity_fixed_from': SplitDateTimeField,
|
||||
'validity_fixed_until': SplitDateTimeField,
|
||||
'hidden_if_available': SafeModelChoiceField,
|
||||
'hidden_if_item_available': SafeModelChoiceField,
|
||||
'grant_membership_type': SafeModelChoiceField,
|
||||
'require_membership_types': SafeModelMultipleChoiceField,
|
||||
}
|
||||
@@ -797,6 +827,8 @@ class ItemVariationForm(I18nModelForm):
|
||||
del self.fields['require_membership']
|
||||
del self.fields['require_membership_types']
|
||||
|
||||
self.fields['free_price_suggestion'].widget.attrs['data-display-dependency'] = '#id_free_price'
|
||||
|
||||
self.meta_fields = []
|
||||
meta_defaults = {}
|
||||
if self.instance.pk:
|
||||
@@ -829,6 +861,7 @@ class ItemVariationForm(I18nModelForm):
|
||||
'value',
|
||||
'active',
|
||||
'default_price',
|
||||
'free_price_suggestion',
|
||||
'original_price',
|
||||
'description',
|
||||
'require_approval',
|
||||
|
||||
@@ -39,7 +39,7 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Q
|
||||
from django.forms import inlineformset_factory
|
||||
from django.forms import formset_factory, inlineformset_factory
|
||||
from django.forms.utils import ErrorDict
|
||||
from django.urls import reverse
|
||||
from django.utils.crypto import get_random_string
|
||||
@@ -48,7 +48,7 @@ from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django_scopes.forms import SafeModelChoiceField
|
||||
from i18nfield.forms import (
|
||||
I18nFormField, I18nFormSetMixin, I18nTextarea, I18nTextInput,
|
||||
I18nForm, I18nFormField, I18nFormSetMixin, I18nTextarea, I18nTextInput,
|
||||
)
|
||||
from phonenumber_field.formfields import PhoneNumberField
|
||||
from pytz import common_timezones
|
||||
@@ -195,14 +195,50 @@ class SafeOrderPositionChoiceField(forms.ModelChoiceField):
|
||||
return f'{op.order.code}-{op.positionid} ({str(op.item) + ((" - " + str(op.variation)) if op.variation else "")})'
|
||||
|
||||
|
||||
class EventMetaPropertyForm(forms.ModelForm):
|
||||
class EventMetaPropertyForm(I18nModelForm):
|
||||
class Meta:
|
||||
model = EventMetaProperty
|
||||
fields = ['name', 'default', 'required', 'protected', 'allowed_values', 'filter_allowed']
|
||||
fields = ['name', 'default', 'required', 'protected', 'filter_public', 'public_label', 'filter_allowed']
|
||||
widgets = {
|
||||
'default': forms.TextInput()
|
||||
'default': forms.TextInput(),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['public_label'].widget.attrs['data-display-dependency'] = '#id_filter_public'
|
||||
|
||||
|
||||
class EventMetaPropertyAllowedValueForm(I18nForm):
|
||||
key = forms.CharField(
|
||||
label=_('Internal name'),
|
||||
max_length=250,
|
||||
required=True
|
||||
)
|
||||
label = I18nFormField(
|
||||
label=_('Public name'),
|
||||
required=False,
|
||||
widget=I18nTextInput,
|
||||
widget_kwargs=dict(attrs={
|
||||
'placeholder': _('Public name'),
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
class I18nBaseFormSet(I18nFormSetMixin, forms.BaseFormSet):
|
||||
# compatibility shim for django-i18nfield library
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.organizer = kwargs.pop('organizer', None)
|
||||
if self.organizer:
|
||||
kwargs['locales'] = self.organizer.settings.get('locales')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
EventMetaPropertyAllowedValueFormSet = formset_factory(
|
||||
EventMetaPropertyAllowedValueForm, formset=I18nBaseFormSet,
|
||||
can_order=True, can_delete=True, extra=0
|
||||
)
|
||||
|
||||
|
||||
class MembershipTypeForm(I18nModelForm):
|
||||
class Meta:
|
||||
|
||||
@@ -393,12 +393,12 @@ class SubEventMetaValueForm(forms.ModelForm):
|
||||
self.default = kwargs.pop('default', None)
|
||||
self.disabled = kwargs.pop('disabled', False)
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.property.allowed_values:
|
||||
if self.property.choices:
|
||||
self.fields['value'] = forms.ChoiceField(
|
||||
label=self.property.name,
|
||||
choices=[
|
||||
('', _('Default ({value})').format(value=self.default or self.property.default) if self.default or self.property.default else ''),
|
||||
] + [(a.strip(), a.strip()) for a in self.property.allowed_values.splitlines()],
|
||||
] + [(a.strip(), a.strip()) for a in self.property.choice_keys],
|
||||
)
|
||||
else:
|
||||
self.fields['value'].label = self.property.name
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
{% extends "pretixcontrol/items/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Delete check-ins" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Delete check-ins" %}</h1>
|
||||
<form action="{% url "control:event.orders.checkinlists.bulk_action" event=request.event.slug organizer=request.event.organizer.slug list=checkinlist.pk %}" method="post" class="form-horizontal" data-asynctask>
|
||||
{% csrf_token %}
|
||||
{% for k, l in request.POST.lists %}
|
||||
{% for v in l %}
|
||||
<input type="hidden" name="{{ k }}" value="{{ v }}">
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<p>
|
||||
{% blocktrans trimmed count count=cnt %}
|
||||
Are you sure you want to permanently delete the check-ins of <strong>one ticket</strong>.
|
||||
{% plural %}
|
||||
Are you sure you want to permanently delete the check-ins of <strong>{{ count }} tickets</strong>?
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<div class="form-group submit-group">
|
||||
<a href="{% url "control:event.orders.checkinlists" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default btn-cancel">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-danger btn-save">
|
||||
{% trans "Delete" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -205,22 +205,27 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if "can_change_orders" in request.eventpermset or "can_checkin_orders" in request.eventpermset %}
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
<span class="fa fa-sign-in" aria-hidden="true"></span>
|
||||
{% trans "Check-In selected attendees" %}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-default btn-save" name="checkout" value="true">
|
||||
<span class="fa fa-sign-out" aria-hidden="true"></span>
|
||||
{% trans "Check-Out selected attendees" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
<button type="submit" class="btn btn-danger btn-save" name="revert" value="true">
|
||||
<span class="fa fa-trash" aria-hidden="true"></span>
|
||||
{% trans "Delete all check-ins of selected attendees" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
<div class="batch-select-actions">
|
||||
{% if "can_change_orders" in request.eventpermset or "can_checkin_orders" in request.eventpermset %}
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
<span class="fa fa-sign-in" aria-hidden="true"></span>
|
||||
{% trans "Check-In selected attendees" %}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-default btn-save" name="checkout" value="true">
|
||||
<span class="fa fa-sign-out" aria-hidden="true"></span>
|
||||
{% trans "Check-Out selected attendees" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if "can_change_orders" in request.eventpermset %}
|
||||
<button type="submit" class="btn btn-danger btn-save" name="revert"
|
||||
formaction="{% url "control:event.orders.checkinlists.bulk_revert" event=request.event.slug organizer=request.event.organizer.slug list=checkinlist.pk %}"
|
||||
data-no-asynctask
|
||||
value="true">
|
||||
<span class="fa fa-trash" aria-hidden="true"></span>
|
||||
{% trans "Delete all check-ins of selected attendees" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endif %}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans with name=checkinlist.name %}Are you sure you want to delete the check-in list <strong>{{ name }}</strong>?{% endblocktrans %}</p>
|
||||
{% if checkinlist.checkins.exists > 0 %}
|
||||
<p>{% blocktrans trimmed with num=checkinlist.checkins.count %}
|
||||
{% if checkinlist.checkins.exists %}
|
||||
<div class="alert alert-warning">{% blocktrans trimmed with num=checkinlist.checkins.count %}
|
||||
This will delete the information of <strong>{{ num }}</strong> check-ins as well.
|
||||
{% endblocktrans %}</p>
|
||||
{% endblocktrans %}</div>
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<a href="{% url "control:event.orders.checkinlists" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
@@ -18,7 +18,11 @@
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-danger btn-save">
|
||||
{% trans "Delete" %}
|
||||
{% if checkinlist.checkins.exists %}
|
||||
{% trans "Delete list and all check-ins" %}
|
||||
{% else %}
|
||||
{% trans "Delete" %}
|
||||
{% endif %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<summary class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<strong>{% trans title %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||
</h4>
|
||||
</summary>
|
||||
<div id="{{ pid }}">
|
||||
|
||||
@@ -316,6 +316,9 @@
|
||||
{% if sform.event_list_available_only %}
|
||||
{% bootstrap_field sform.event_list_available_only layout="control" %}
|
||||
{% endif %}
|
||||
{% if sform.event_list_filters %}
|
||||
{% bootstrap_field sform.event_list_filters layout="control" %}
|
||||
{% endif %}
|
||||
{% if sform.event_calendar_future_only %}
|
||||
{% bootstrap_field sform.event_calendar_future_only layout="control" %}
|
||||
{% endif %}
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.status %}
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.date_from %}
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.date_until %}
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.organizer %}
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,14 @@
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not request.event.has_subevents and object.hidden_if_item_available and object.hidden_if_item_available.check_quotas.0 == 100 %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed %}
|
||||
This product is currently not being shown since you configured below that it should only be visible
|
||||
if a certain other product is already sold out.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block inside %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-12">
|
||||
<strong class="panel-title">
|
||||
<span class="fa fa-fw chevron"></span>
|
||||
<span class="fa fa-warning text-danger hidden variation-error"></span>
|
||||
<span class="variation-name">
|
||||
Variation name
|
||||
@@ -72,6 +71,7 @@
|
||||
{% bootstrap_field form.active layout="control" %}
|
||||
{% bootstrap_field form.value layout="control" %}
|
||||
{% bootstrap_field form.default_price addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field form.free_price_suggestion addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field form.original_price addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field form.description layout="control" %}
|
||||
{% if form.meta_fields %}
|
||||
@@ -124,7 +124,6 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-xs-12">
|
||||
<strong class="panel-title">
|
||||
<span class="fa fa-fw chevron"></span>
|
||||
<span class="fa fa-warning text-danger hidden variation-error"></span>
|
||||
<span class="variation-name">
|
||||
{% trans "New variation" %}
|
||||
@@ -170,6 +169,7 @@
|
||||
{% bootstrap_field formset.empty_form.active layout="control" %}
|
||||
{% bootstrap_field formset.empty_form.value layout="control" %}
|
||||
{% bootstrap_field formset.empty_form.default_price addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field formset.empty_form.free_price_suggestion addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field formset.empty_form.original_price addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field formset.empty_form.description layout="control" %}
|
||||
{% if formset.empty_form.meta_fields %}
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
{% bootstrap_field form.default_price addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field form.tax_rule layout="control" %}
|
||||
{% bootstrap_field form.free_price layout="control" %}
|
||||
{% bootstrap_field form.free_price_suggestion addon_after=request.event.currency layout="control" %}
|
||||
{% bootstrap_field form.original_price addon_after=request.event.currency layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
@@ -168,7 +169,10 @@
|
||||
{% endif %}
|
||||
{% bootstrap_field form.allow_cancel layout="control" %}
|
||||
{% bootstrap_field form.allow_waitinglist layout="control" %}
|
||||
{% bootstrap_field form.hidden_if_available layout="control" %}
|
||||
{% if form.hidden_if_available %}
|
||||
{% bootstrap_field form.hidden_if_available layout="control" %}
|
||||
{% endif %}
|
||||
{% bootstrap_field form.hidden_if_item_available layout="control" %}
|
||||
</fieldset>
|
||||
{% for v in formsets.values %}
|
||||
<fieldset>
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
<strong>{% trans "Invoice information" %} {% if not request.event.settings.invoice_address_required %}
|
||||
{% trans "(optional)" %}
|
||||
{% endif %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||
</h4>
|
||||
</summary>
|
||||
<div id="invoice">
|
||||
@@ -42,7 +41,6 @@
|
||||
<strong>{{ pos.item }}{% if pos.variation %}
|
||||
– {{ pos.variation }}
|
||||
{% endif %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||
</h4>
|
||||
</summary>
|
||||
<div id="cp{{ pos.id }}">
|
||||
|
||||
@@ -589,9 +589,9 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{% elif q.type == "M" %}
|
||||
{{ q.answer|rich_text_snippet }}
|
||||
{{ q.answer.to_string_i18n|rich_text_snippet }}
|
||||
{% else %}
|
||||
{{ q.answer|linebreaksbr }}
|
||||
{{ q.answer.to_string_i18n|linebreaksbr }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<em>{% trans "not answered" %}</em>
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.status %}
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.date_from %}
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.date_until %}
|
||||
</div>
|
||||
{% for mf in meta_fields %}
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field mf %}
|
||||
|
||||
@@ -14,29 +14,56 @@
|
||||
<span class="fa fa-plus"></span>
|
||||
{% trans "Create a new property" %}
|
||||
</a>
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Property" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for p in properties %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<td><strong>
|
||||
<a href="{% url "control:organizer.property.edit" organizer=request.organizer.slug property=p.id %}">
|
||||
{{ p.name }}
|
||||
</a>
|
||||
</strong></td>
|
||||
<td class="text-right flip">
|
||||
<a href="{% url "control:organizer.property.edit" organizer=request.organizer.slug property=p.id %}"
|
||||
class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "control:organizer.property.delete" organizer=request.organizer.slug property=p.id %}"
|
||||
class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<th>{% trans "Property" %}</th>
|
||||
<th class="iconcol"></th>
|
||||
<th class="iconcol"></th>
|
||||
<th class="iconcol"></th>
|
||||
<th class="action-col-2"></th>
|
||||
<th class="action-col-2"></th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody data-dnd-url="{% url "control:organizer.properties.reorder" organizer=request.organizer.slug %}">
|
||||
{% for p in properties %}
|
||||
<tr data-dnd-id="{{ p.pk }}">
|
||||
<td><strong>
|
||||
<a href="{% url "control:organizer.property.edit" organizer=request.organizer.slug property=p.id %}">
|
||||
{{ p.name }}
|
||||
</a>
|
||||
</strong></td>
|
||||
<td>
|
||||
{% if p.filter_allowed %}
|
||||
<span class="fa fa-filter text-muted" data-toggle="tooltip" title="{% trans "Can be used for filtering" %}"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if p.filter_public %}
|
||||
<span class="fa fa-eye text-muted" data-toggle="tooltip" title="{% trans "Show filter option to customers" %}"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if p.protected %}
|
||||
<span class="fa fa-lock text-muted" data-toggle="tooltip" title="{% trans "Can only be changed by organizer-level administrators" %}"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<button formaction="{% url "control:organizer.property.up" organizer=request.organizer.slug property=p.id %}" class="btn btn-default btn-sm sortable-up"{% if forloop.counter0 == 0 and not page_obj.has_previous %} disabled{% endif %}><i class="fa fa-arrow-up"></i></button>
|
||||
<button formaction="{% url "control:organizer.property.down" organizer=request.organizer.slug property=p.id %}" class="btn btn-default btn-sm sortable-down"{% if forloop.revcounter0 == 0 and not page_obj.has_next %} disabled{% endif %}><i class="fa fa-arrow-down"></i></button>
|
||||
<span class="dnd-container"></span>
|
||||
</td>
|
||||
<td class="text-right flip">
|
||||
<a href="{% url "control:organizer.property.edit" organizer=request.organizer.slug property=p.id %}"
|
||||
class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "control:organizer.property.delete" organizer=request.organizer.slug property=p.id %}"
|
||||
class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends "pretixcontrol/organizers/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load formset_tags %}
|
||||
{% load bootstrap3 %}
|
||||
{% block inner %}
|
||||
{% if property %}
|
||||
@@ -10,6 +11,78 @@
|
||||
<form class="form-horizontal" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form layout="control" %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">
|
||||
{% trans "Allowed values" %}<br>
|
||||
<span class="optional">{% trans "Optional" %}</span>
|
||||
</label>
|
||||
<div class="col-md-9">
|
||||
<p class="help-block">{% trans "If you keep this empty, all input will be allowed." %}</p>
|
||||
<div class="formset tax-rules-formset" data-formset data-formset-prefix="{{ formset.prefix }}">
|
||||
{{ formset.management_form }}
|
||||
{% bootstrap_formset_errors formset %}
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="row tax-rule-line" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ formset.empty_form.id }}
|
||||
{% bootstrap_field formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field formset.empty_form.ORDER form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-5">
|
||||
{% bootstrap_field formset.empty_form.key layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-5">
|
||||
{% bootstrap_field formset.empty_form.label layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-2 text-right flip">
|
||||
<button type="button" class="btn btn-default" data-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default" data-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<div data-formset-body class="tax-rule-lines">
|
||||
{% for form in formset %}
|
||||
{% bootstrap_form_errors form %}
|
||||
<div class="row tax-rule-line" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ form.id }}
|
||||
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field form.ORDER form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-5">
|
||||
{% bootstrap_field form.key layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-5">
|
||||
{% bootstrap_field form.label layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 col-lg-2 text-right flip">
|
||||
<button type="button" class="btn btn-default" data-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default" data-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row tax-rule-line" data-formset-form>
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-default" data-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add a new value" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
@@ -6,26 +6,48 @@
|
||||
<ul class="pagination">
|
||||
{% if is_paginated %}
|
||||
{% if page_obj.has_previous %}
|
||||
{% if page_obj.previous_page_number > 1 %}
|
||||
<li>
|
||||
<a href="?{% url_replace request 'page' page_obj.num_pages %}" title="{% trans "Go to page 1" %}">
|
||||
<span class="fa fa-angle-double-left"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="?{% url_replace request 'page' page_obj.previous_page_number %}">
|
||||
<span>«</span>
|
||||
<a href="?{% url_replace request 'page' page_obj.previous_page_number %}" title="{% blocktrans with page=page_obj.previous_page_number %}Go to page {{ page }}{% endblocktrans %}">
|
||||
<span class="fa fa-angle-left"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="page-current"><a>
|
||||
<li class="page-current">
|
||||
<a {% if page_obj.paginator.count %}
|
||||
class="pagination-selection"
|
||||
data-href="?{% url_replace request 'page' '_PAGE_' %}"
|
||||
data-max="{{ page_obj.paginator.num_pages }}"
|
||||
title="{% trans "Click to choose a page" %}"
|
||||
href="#"
|
||||
{% endif %}>
|
||||
{% blocktrans trimmed with page=page_obj.number of=page_obj.paginator.num_pages count=page_obj.paginator.count|intcomma %}
|
||||
Page {{ page }} of {{ of }} ({{ count }} elements)
|
||||
{% endblocktrans %}
|
||||
</a></li>
|
||||
</a>
|
||||
</li>
|
||||
{% if page_obj.has_next %}
|
||||
<li>
|
||||
<a href="?{% url_replace request 'page' page_obj.next_page_number %}">
|
||||
<span>»</span>
|
||||
<a href="?{% url_replace request 'page' page_obj.next_page_number %}" title="{% blocktrans with page=page_obj.next_page_number %}Go to page {{ page }}{% endblocktrans %}">
|
||||
<span class="fa fa-angle-right"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page_obj.paginator.count and page_obj.paginator.num_pages > page_obj.next_page_number %}
|
||||
<li>
|
||||
<a href="?{% url_replace request 'page' page_obj.paginator.num_pages %}" title="{% blocktrans with page=page_obj.paginator.num_pages %}Go to page {{ page }}{% endblocktrans %}">
|
||||
<span class="fa fa-angle-double-right"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if page_obj.paginator.count > 1 %}
|
||||
{% if page_obj.paginator.count > 1 %}
|
||||
<li class="page-current"><a>
|
||||
{% blocktrans trimmed with count=page_obj.paginator.count|intcomma %}
|
||||
{{ count }} elements
|
||||
|
||||
@@ -133,6 +133,11 @@
|
||||
{{ s.name }}</a></strong><br>
|
||||
<small class="text-muted">
|
||||
#{{ s.pk }}
|
||||
{% for k, v in s.meta_data.items %}
|
||||
{% if v %}
|
||||
<small class="text-muted">· {{ k }}: {{ v }}</small>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</small>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -126,6 +126,12 @@ urlpatterns = [
|
||||
name='organizer.property.edit'),
|
||||
re_path(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/delete$', organizer.EventMetaPropertyDeleteView.as_view(),
|
||||
name='organizer.property.delete'),
|
||||
re_path(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/up$', organizer.meta_property_move_up,
|
||||
name='organizer.property.up'),
|
||||
re_path(r'^organizer/(?P<organizer>[^/]+)/property/(?P<property>[^/]+)/down$', organizer.meta_property_move_down,
|
||||
name='organizer.property.down'),
|
||||
re_path(r'^organizer/(?P<organizer>[^/]+)/property/reorder$', organizer.reorder_meta_properties,
|
||||
name='organizer.properties.reorder'),
|
||||
re_path(r'^organizer/(?P<organizer>[^/]+)/membershiptypes$', organizer.MembershipTypeListView.as_view(), name='organizer.membershiptypes'),
|
||||
re_path(r'^organizer/(?P<organizer>[^/]+)/membershiptype/add$', organizer.MembershipTypeCreateView.as_view(),
|
||||
name='organizer.membershiptype.add'),
|
||||
@@ -438,6 +444,7 @@ urlpatterns = [
|
||||
re_path(r'^checkinlists/select2$', typeahead.checkinlist_select2, name='event.orders.checkinlists.select2'),
|
||||
re_path(r'^checkinlists/(?P<list>\d+)/$', checkin.CheckInListShow.as_view(), name='event.orders.checkinlists.show'),
|
||||
re_path(r'^checkinlists/(?P<list>\d+)/simulator$', checkin.CheckInListSimulator.as_view(), name='event.orders.checkinlists.simulator'),
|
||||
re_path(r'^checkinlists/(?P<list>\d+)/bulk_revert$', checkin.CheckInListBulkRevertConfirmView.as_view(), name='event.orders.checkinlists.bulk_revert'),
|
||||
re_path(r'^checkinlists/(?P<list>\d+)/bulk_action$', checkin.CheckInListBulkActionView.as_view(), name='event.orders.checkinlists.bulk_action'),
|
||||
re_path(r'^checkinlists/(?P<list>\d+)/change$', checkin.CheckinListUpdate.as_view(),
|
||||
name='event.orders.checkinlists.edit'),
|
||||
|
||||
@@ -266,7 +266,7 @@ class Forgot(TemplateView):
|
||||
has_redis = settings.HAS_REDIS
|
||||
|
||||
try:
|
||||
user = User.objects.get(email__iexact=email)
|
||||
user = User.objects.get(is_active=True, auth_backend='native', email__iexact=email)
|
||||
|
||||
if has_redis:
|
||||
from django_redis import get_redis_connection
|
||||
@@ -330,7 +330,7 @@ class Recover(TemplateView):
|
||||
if request.user.is_authenticated:
|
||||
return redirect(request.GET.get("next", 'control:index'))
|
||||
try:
|
||||
user = User.objects.get(id=self.request.GET.get('id'), auth_backend='native')
|
||||
user = User.objects.get(id=self.request.GET.get('id'), is_active=True, auth_backend='native')
|
||||
except User.DoesNotExist:
|
||||
return self.invalid('unknownuser')
|
||||
if not default_token_generator.check_token(user, self.request.GET.get('token')):
|
||||
|
||||
@@ -45,7 +45,7 @@ from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import is_aware, make_aware, now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import FormView, ListView
|
||||
from django.views.generic import FormView, ListView, TemplateView
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.api.views.checkin import _redeem_process
|
||||
@@ -191,9 +191,23 @@ class CheckInListShow(EventPermissionRequiredMixin, PaginationMixin, CheckInList
|
||||
return ctx
|
||||
|
||||
|
||||
class CheckInListBulkRevertConfirmView(CheckInListQueryMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = "pretixcontrol/checkin/bulk_revert_confirm.html"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.list = get_object_or_404(self.request.event.checkin_lists.all(), pk=kwargs.get("list"))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(
|
||||
**kwargs,
|
||||
cnt=self.get_queryset().count(),
|
||||
checkinlist=self.list,
|
||||
)
|
||||
|
||||
|
||||
class CheckInListBulkActionView(CheckInListQueryMixin, EventPermissionRequiredMixin, AsyncPostView):
|
||||
permission = ('can_change_orders', 'can_checkin_orders')
|
||||
context_object_name = 'device'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.list = get_object_or_404(self.request.event.checkin_lists.all(), pk=kwargs.get("list"))
|
||||
@@ -216,14 +230,15 @@ class CheckInListBulkActionView(CheckInListQueryMixin, EventPermissionRequiredMi
|
||||
if op.order.status == Order.STATUS_PAID or (
|
||||
(self.list.include_pending or op.order.valid_if_pending) and op.order.status == Order.STATUS_PENDING
|
||||
):
|
||||
Checkin.objects.filter(position=op, list=self.list).delete()
|
||||
op.order.log_action('pretix.event.checkin.reverted', data={
|
||||
'position': op.id,
|
||||
'positionid': op.positionid,
|
||||
'list': self.list.pk,
|
||||
'web': True
|
||||
}, user=request.user)
|
||||
op.order.touch()
|
||||
_, deleted = Checkin.objects.filter(position=op, list=self.list).delete()
|
||||
if deleted:
|
||||
op.order.log_action('pretix.event.checkin.reverted', data={
|
||||
'position': op.id,
|
||||
'positionid': op.positionid,
|
||||
'list': self.list.pk,
|
||||
'web': True
|
||||
}, user=request.user)
|
||||
op.order.touch()
|
||||
|
||||
return 'reverted', request.POST.get('returnquery')
|
||||
else:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
import csv
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
@@ -157,6 +158,14 @@ class ProcessView(EventPermissionRequiredMixin, AsyncAction, FormView):
|
||||
)
|
||||
return parse_csv(self.file.file, 1024 * 1024, "replace", charset=charset)
|
||||
|
||||
@cached_property
|
||||
def parsed_list(self):
|
||||
try:
|
||||
return list(self.parsed)
|
||||
except csv.Error:
|
||||
logger.exception("Could not parse full CSV file")
|
||||
return None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'async_id' in request.GET and settings.HAS_CELERY:
|
||||
return self.get_result(request)
|
||||
@@ -174,7 +183,7 @@ class ProcessView(EventPermissionRequiredMixin, AsyncAction, FormView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if 'async_id' in request.GET and settings.HAS_CELERY:
|
||||
return self.get_result(request)
|
||||
if not self.parsed:
|
||||
if not self.parsed or not self.parsed_list:
|
||||
messages.error(request, _('We\'ve been unable to parse the uploaded file as a CSV file.'))
|
||||
return redirect(reverse('control:event.orders.import', kwargs={
|
||||
'event': request.event.slug,
|
||||
@@ -193,5 +202,5 @@ class ProcessView(EventPermissionRequiredMixin, AsyncAction, FormView):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['file'] = self.file
|
||||
ctx['parsed'] = self.parsed
|
||||
ctx['sample_rows'] = list(self.parsed)[:3]
|
||||
ctx['sample_rows'] = self.parsed_list[:3]
|
||||
return ctx
|
||||
|
||||
@@ -1141,6 +1141,9 @@ class OrderRefundView(OrderView):
|
||||
messages.error(self.request, _('You entered an order that could not be found.'))
|
||||
is_valid = False
|
||||
else:
|
||||
if order.event.currency != self.request.event.currency:
|
||||
messages.error(self.request, _('You entered an order in an event with a different currency.'))
|
||||
is_valid = False
|
||||
refunds.append(OrderRefund(
|
||||
order=self.order,
|
||||
payment=None,
|
||||
@@ -1891,7 +1894,7 @@ class OrderChange(OrderView):
|
||||
ocm.cancel_fee(f)
|
||||
continue
|
||||
|
||||
if f.form.cleaned_data['value'] != f.value:
|
||||
if f.form.cleaned_data['value'] is not None and f.form.cleaned_data['value'] != f.value:
|
||||
ocm.change_fee(f, f.form.cleaned_data['value'])
|
||||
|
||||
if f.form.cleaned_data['tax_rule'] and f.form.cleaned_data['tax_rule'] != f.tax_rule:
|
||||
|
||||
@@ -37,8 +37,10 @@ import re
|
||||
from datetime import time, timedelta
|
||||
from decimal import Decimal
|
||||
from hashlib import sha1
|
||||
from json import JSONDecodeError
|
||||
|
||||
import bleach
|
||||
import dateutil
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
@@ -51,7 +53,9 @@ from django.db.models import (
|
||||
)
|
||||
from django.db.models.functions import Coalesce, Greatest
|
||||
from django.forms import DecimalField
|
||||
from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
|
||||
from django.http import (
|
||||
Http404, HttpResponse, HttpResponseBadRequest, JsonResponse,
|
||||
)
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.formats import date_format
|
||||
@@ -59,6 +63,7 @@ from django.utils.functional import cached_property
|
||||
from django.utils.timezone import get_current_timezone, now
|
||||
from django.utils.translation import gettext, gettext_lazy as _
|
||||
from django.views import View
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.generic import (
|
||||
CreateView, DetailView, FormView, ListView, TemplateView, UpdateView,
|
||||
)
|
||||
@@ -96,17 +101,19 @@ from pretix.control.forms.filter import (
|
||||
from pretix.control.forms.orders import ExporterForm
|
||||
from pretix.control.forms.organizer import (
|
||||
CustomerCreateForm, CustomerUpdateForm, DeviceBulkEditForm, DeviceForm,
|
||||
EventMetaPropertyForm, GateForm, GiftCardAcceptanceInviteForm,
|
||||
GiftCardCreateForm, GiftCardUpdateForm, MailSettingsForm,
|
||||
MembershipTypeForm, MembershipUpdateForm, OrganizerDeleteForm,
|
||||
OrganizerFooterLinkFormset, OrganizerForm, OrganizerSettingsForm,
|
||||
OrganizerUpdateForm, ReusableMediumCreateForm, ReusableMediumUpdateForm,
|
||||
SSOClientForm, SSOProviderForm, TeamForm, WebHookForm,
|
||||
EventMetaPropertyAllowedValueFormSet, EventMetaPropertyForm, GateForm,
|
||||
GiftCardAcceptanceInviteForm, GiftCardCreateForm, GiftCardUpdateForm,
|
||||
MailSettingsForm, MembershipTypeForm, MembershipUpdateForm,
|
||||
OrganizerDeleteForm, OrganizerFooterLinkFormset, OrganizerForm,
|
||||
OrganizerSettingsForm, OrganizerUpdateForm, ReusableMediumCreateForm,
|
||||
ReusableMediumUpdateForm, SSOClientForm, SSOProviderForm, TeamForm,
|
||||
WebHookForm,
|
||||
)
|
||||
from pretix.control.forms.rrule import RRuleForm
|
||||
from pretix.control.logdisplay import OVERVIEW_BANLIST
|
||||
from pretix.control.permissions import (
|
||||
AdministratorPermissionRequiredMixin, OrganizerPermissionRequiredMixin,
|
||||
organizer_permission_required,
|
||||
)
|
||||
from pretix.control.signals import nav_organizer
|
||||
from pretix.control.views import PaginationMixin
|
||||
@@ -1636,7 +1643,10 @@ class ExportMixin:
|
||||
for k in initial:
|
||||
if initial[k] and k in test_form.fields:
|
||||
try:
|
||||
initial[k] = test_form.fields[k].to_python(initial[k])
|
||||
if isinstance(test_form.fields[k], forms.SplitDateTimeField):
|
||||
initial[k] = dateutil.parser.parse(initial[k])
|
||||
else:
|
||||
initial[k] = test_form.fields[k].to_python(initial[k])
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
@@ -2039,14 +2049,54 @@ class EventMetaPropertyListView(OrganizerDetailViewMixin, OrganizerPermissionReq
|
||||
return self.request.organizer.meta_properties.all()
|
||||
|
||||
|
||||
class EventMetaPropertyCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
model = EventMetaProperty
|
||||
class EventMetaPropertyEditorMixin:
|
||||
template_name = 'pretixcontrol/organizers/property_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
form_class = EventMetaPropertyForm
|
||||
|
||||
@cached_property
|
||||
def formset(self):
|
||||
return EventMetaPropertyAllowedValueFormSet(
|
||||
data=self.request.POST if self.request.method == "POST" else None,
|
||||
organizer=self.request.organizer,
|
||||
initial=(self.object.choices or []) if self.object else [],
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['formset'] = self.formset
|
||||
return ctx
|
||||
|
||||
def get_form_kwargs(self):
|
||||
return {
|
||||
**super().get_form_kwargs(),
|
||||
'event': self.request.organizer,
|
||||
}
|
||||
|
||||
def is_default_valid(self):
|
||||
choice_keys = [
|
||||
f.cleaned_data.get("key") for f in self.formset.ordered_forms if f not in self.formset.deleted_forms
|
||||
]
|
||||
default = self.form.cleaned_data["default"]
|
||||
if default and choice_keys and default not in choice_keys:
|
||||
messages.error(self.request, _("You cannot set a default value that is not a valid value."))
|
||||
return False
|
||||
return True
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(self.get_queryset())
|
||||
self.form = self.get_form()
|
||||
if self.form.is_valid() and self.formset.is_valid() and self.is_default_valid():
|
||||
return self.form_valid(self.form)
|
||||
else:
|
||||
return self.form_invalid(self.form)
|
||||
|
||||
|
||||
class EventMetaPropertyCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, EventMetaPropertyEditorMixin, CreateView):
|
||||
model = EventMetaProperty
|
||||
permission = 'can_change_organizer_settings'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return get_object_or_404(EventMetaProperty, organizer=self.request.organizer, pk=self.kwargs.get('property'))
|
||||
return EventMetaProperty()
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('control:organizer.properties', kwargs={
|
||||
@@ -2056,6 +2106,9 @@ class EventMetaPropertyCreateView(OrganizerDetailViewMixin, OrganizerPermissionR
|
||||
def form_valid(self, form):
|
||||
messages.success(self.request, _('The property has been created.'))
|
||||
form.instance.organizer = self.request.organizer
|
||||
form.instance.choices = [
|
||||
f.cleaned_data for f in self.formset.ordered_forms if f not in self.formset.deleted_forms
|
||||
]
|
||||
ret = super().form_valid(form)
|
||||
form.instance.log_action('pretix.property.created', user=self.request.user, data={
|
||||
k: getattr(self.object, k) for k in form.changed_data
|
||||
@@ -2067,12 +2120,10 @@ class EventMetaPropertyCreateView(OrganizerDetailViewMixin, OrganizerPermissionR
|
||||
return super().form_invalid(form)
|
||||
|
||||
|
||||
class EventMetaPropertyUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, UpdateView):
|
||||
class EventMetaPropertyUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, EventMetaPropertyEditorMixin, UpdateView):
|
||||
model = EventMetaProperty
|
||||
template_name = 'pretixcontrol/organizers/property_edit.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
context_object_name = 'property'
|
||||
form_class = EventMetaPropertyForm
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return get_object_or_404(EventMetaProperty, organizer=self.request.organizer, pk=self.kwargs.get('property'))
|
||||
@@ -2083,7 +2134,10 @@ class EventMetaPropertyUpdateView(OrganizerDetailViewMixin, OrganizerPermissionR
|
||||
})
|
||||
|
||||
def form_valid(self, form):
|
||||
if form.has_changed():
|
||||
form.instance.choices = [
|
||||
f.cleaned_data for f in self.formset.ordered_forms if f not in self.formset.deleted_forms
|
||||
]
|
||||
if form.has_changed() or self.formset.has_changed():
|
||||
self.object.log_action('pretix.property.changed', user=self.request.user, data={
|
||||
k: getattr(self.object, k)
|
||||
for k in form.changed_data
|
||||
@@ -2120,6 +2174,75 @@ class EventMetaPropertyDeleteView(OrganizerDetailViewMixin, OrganizerPermissionR
|
||||
return redirect(success_url)
|
||||
|
||||
|
||||
def meta_property_move(request, property, up=True):
|
||||
property = get_object_or_404(request.organizer.meta_properties, id=property)
|
||||
properties = list(request.organizer.meta_properties.order_by("position"))
|
||||
|
||||
index = properties.index(property)
|
||||
if index != 0 and up:
|
||||
properties[index - 1], properties[index] = properties[index], properties[index - 1]
|
||||
elif index != len(properties) - 1 and not up:
|
||||
properties[index + 1], properties[index] = properties[index], properties[index + 1]
|
||||
|
||||
for i, prop in enumerate(properties):
|
||||
if prop.position != i:
|
||||
prop.position = i
|
||||
prop.save()
|
||||
prop.log_action(
|
||||
'pretix.property.reordered', user=request.user, data={
|
||||
'position': i,
|
||||
}
|
||||
)
|
||||
messages.success(request, _('The order of properties has been updated.'))
|
||||
|
||||
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@require_http_methods(["POST"])
|
||||
def meta_property_move_up(request, organizer, property):
|
||||
meta_property_move(request, property, up=True)
|
||||
return redirect('control:organizer.properties',
|
||||
organizer=request.organizer.slug)
|
||||
|
||||
|
||||
@organizer_permission_required("can_change_organizer_settings")
|
||||
@require_http_methods(["POST"])
|
||||
def meta_property_move_down(request, organizer, property):
|
||||
meta_property_move(request, property, up=False)
|
||||
return redirect('control:organizer.properties',
|
||||
organizer=request.organizer.slug)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@organizer_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_meta_properties(request, organizer):
|
||||
try:
|
||||
ids = json.loads(request.body.decode('utf-8'))['ids']
|
||||
except (JSONDecodeError, KeyError, ValueError):
|
||||
return HttpResponseBadRequest("expected JSON: {ids:[]}")
|
||||
|
||||
input_meta_properties = list(request.organizer.meta_properties.filter(id__in=[i for i in ids if i.isdigit()]))
|
||||
|
||||
if len(input_meta_properties) != len(ids):
|
||||
raise Http404(_("Some of the provided object ids are invalid."))
|
||||
|
||||
if len(input_meta_properties) != request.organizer.meta_properties.count():
|
||||
raise Http404(_("Not all objects have been selected."))
|
||||
|
||||
for c in input_meta_properties:
|
||||
pos = ids.index(str(c.pk))
|
||||
if pos != c.position: # Save unneccessary UPDATE queries
|
||||
c.position = pos
|
||||
c.save(update_fields=['position'])
|
||||
c.log_action(
|
||||
'pretix.property.reordered', user=request.user, data={
|
||||
'position': pos,
|
||||
}
|
||||
)
|
||||
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
class LogView(OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
template_name = 'pretixcontrol/organizers/logs.html'
|
||||
permission = 'can_change_organizer_settings'
|
||||
|
||||
@@ -120,7 +120,10 @@ class SubEventList(EventPermissionRequiredMixin, PaginationMixin, SubEventQueryM
|
||||
permission = 'can_change_settings'
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset(True)
|
||||
return super().get_queryset(True).prefetch_related(
|
||||
'meta_values',
|
||||
'meta_values__property',
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
@@ -755,16 +758,16 @@ class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, Asyn
|
||||
initial['time_to'] = i.date_to.astimezone(tz).time() if i.date_to else None
|
||||
initial['time_admission'] = i.date_admission.astimezone(tz).time() if i.date_admission else None
|
||||
initial['rel_presale_start'] = RelativeDateWrapper(RelativeDate(
|
||||
days_before=(i.date_from.astimezone(tz).date() - i.presale_start.astimezone(tz).date()).days,
|
||||
days=(i.date_from.astimezone(tz).date() - i.presale_start.astimezone(tz).date()).days,
|
||||
base_date_name='date_from',
|
||||
time=i.presale_start.astimezone(tz).time(),
|
||||
minutes_before=None
|
||||
minutes=None
|
||||
)) if i.presale_start else None
|
||||
initial['rel_presale_end'] = RelativeDateWrapper(RelativeDate(
|
||||
days_before=(i.date_from.astimezone(tz).date() - i.presale_end.astimezone(tz).date()).days,
|
||||
days=(i.date_from.astimezone(tz).date() - i.presale_end.astimezone(tz).date()).days,
|
||||
base_date_name='date_from',
|
||||
time=i.presale_end.astimezone(tz).time(),
|
||||
minutes_before=None
|
||||
minutes=None
|
||||
)) if i.presale_end else None
|
||||
else:
|
||||
kwargs['instance'] = SubEvent(event=self.request.event)
|
||||
|
||||
@@ -5,7 +5,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 12:47+0000\n"
|
||||
"PO-Revision-Date: 2023-10-27 07:35+0000\n"
|
||||
"PO-Revision-Date: 2023-11-03 04:00+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/"
|
||||
">\n"
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.1\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
"X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
@@ -4255,7 +4255,7 @@ msgstr "Produktbild"
|
||||
|
||||
#: pretix/base/models/items.py:491
|
||||
msgid "Only show after sellout of"
|
||||
msgstr "Nicht anzeigen, wenn anderes Kontingent verfügbar"
|
||||
msgstr "Nicht anzeigen, wenn anderes Produkt verfügbar"
|
||||
|
||||
#: pretix/base/models/items.py:492
|
||||
msgid ""
|
||||
@@ -16562,7 +16562,7 @@ msgstr "Geräte-ID"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:6
|
||||
msgid "Receipt ID"
|
||||
msgstr "Transaktionsnummer"
|
||||
msgstr "Belegnummer"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:11
|
||||
msgid "ID"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 12:47+0000\n"
|
||||
"PO-Revision-Date: 2023-10-27 07:35+0000\n"
|
||||
"PO-Revision-Date: 2023-11-03 04:00+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||
"pretix/pretix/de_Informal/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.1\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -4252,7 +4252,7 @@ msgstr "Produktbild"
|
||||
|
||||
#: pretix/base/models/items.py:491
|
||||
msgid "Only show after sellout of"
|
||||
msgstr "Nicht anzeigen, wenn anderes Kontingent verfügbar"
|
||||
msgstr "Nicht anzeigen, wenn anderes Produkt verfügbar"
|
||||
|
||||
#: pretix/base/models/items.py:492
|
||||
msgid ""
|
||||
@@ -16535,7 +16535,7 @@ msgstr "Geräte-ID"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:6
|
||||
msgid "Receipt ID"
|
||||
msgstr "Transaktionsnummer"
|
||||
msgstr "Belegnummer"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:11
|
||||
msgid "ID"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 12:47+0000\n"
|
||||
"PO-Revision-Date: 2023-09-27 06:59+0000\n"
|
||||
"Last-Translator: Igor Támara <igor@tamarapatino.org>\n"
|
||||
"PO-Revision-Date: 2023-11-07 14:00+0000\n"
|
||||
"Last-Translator: Zona Vip <contacto@zonavip.mx>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.0.2\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -455,7 +455,7 @@ msgstr "Reembolso del pago completado"
|
||||
|
||||
#: pretix/api/webhooks.py:281
|
||||
msgid "Refund of payment canceled"
|
||||
msgstr "Reembolso del pago anulado."
|
||||
msgstr "Reembolso del pago anulado"
|
||||
|
||||
#: pretix/api/webhooks.py:285
|
||||
msgid "Refund of payment failed"
|
||||
@@ -526,7 +526,7 @@ msgstr "La tienda ha sido desconectada"
|
||||
|
||||
#: pretix/api/webhooks.py:346
|
||||
msgid "Test-Mode of shop has been activated"
|
||||
msgstr "Modo de pruebas de la tienda ha sido activado."
|
||||
msgstr "Modo de pruebas de la tienda ha sido activado"
|
||||
|
||||
#: pretix/api/webhooks.py:350
|
||||
msgid "Test-Mode of shop has been deactivated"
|
||||
@@ -1575,7 +1575,7 @@ msgstr "Activo"
|
||||
#: pretix/control/forms/discounts.py:87 pretix/control/forms/event.py:955
|
||||
#: pretix/control/forms/item.py:545 pretix/control/forms/item.py:781
|
||||
msgid "Sales channels"
|
||||
msgstr "Canales de ventas"
|
||||
msgstr "Canal de ventas"
|
||||
|
||||
#: pretix/base/exporters/items.py:74 pretix/base/models/items.py:420
|
||||
#: pretix/base/models/items.py:1015
|
||||
@@ -1984,7 +1984,7 @@ msgstr "Pagado con {method}"
|
||||
#: pretix/base/exporters/orderlist.py:435
|
||||
#: pretix/base/exporters/orderlist.py:846
|
||||
msgid "Fee type"
|
||||
msgstr "Tipo de tarifa"
|
||||
msgstr "Tarifa por billete"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:437
|
||||
#: pretix/base/exporters/orderlist.py:555
|
||||
@@ -2027,8 +2027,9 @@ msgstr "cancelado"
|
||||
#: pretix/base/exporters/orderlist.py:539
|
||||
#: pretix/base/exporters/orderlist.py:839
|
||||
#: pretix/plugins/checkinlists/exporters.py:733
|
||||
#, fuzzy
|
||||
msgid "Position ID"
|
||||
msgstr "ID de la Posición"
|
||||
msgstr "Posición"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:547
|
||||
#: pretix/base/exporters/orderlist.py:850
|
||||
@@ -2095,7 +2096,7 @@ msgstr "Fecha de inicio"
|
||||
#: pretix/plugins/checkinlists/exporters.py:493
|
||||
#: pretix/plugins/checkinlists/exporters.py:678
|
||||
msgid "End date"
|
||||
msgstr "Fecha de fin"
|
||||
msgstr "Fecha final"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:551
|
||||
#: pretix/base/exporters/orderlist.py:843 pretix/base/models/items.py:674
|
||||
@@ -3010,9 +3011,9 @@ msgid "Invalid placeholder(s): %(value)s"
|
||||
msgstr "Persona(s) interesada(s) inválida(s): %(value)s"
|
||||
|
||||
#: pretix/base/forms/widgets.py:67
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "Sample: %s"
|
||||
msgstr "Ciudad de ejemplo"
|
||||
msgstr "Ciudad de ejemplo: %s"
|
||||
|
||||
#: pretix/base/forms/widgets.py:70
|
||||
#, fuzzy, python-brace-format
|
||||
@@ -3476,14 +3477,12 @@ msgid "Server error"
|
||||
msgstr "Error interno del servidor"
|
||||
|
||||
#: pretix/base/models/checkin.py:367
|
||||
#, fuzzy
|
||||
msgid "Ticket blocked"
|
||||
msgstr "Código de ticket"
|
||||
msgstr "Ticket bloqueado"
|
||||
|
||||
#: pretix/base/models/checkin.py:368
|
||||
#, fuzzy
|
||||
msgid "Ticket not valid at this time"
|
||||
msgstr "Este recibo no es válido para esta fecha de evento."
|
||||
msgstr "Ticket no válido en este momento"
|
||||
|
||||
#: pretix/base/models/customers.py:55
|
||||
#, fuzzy
|
||||
@@ -5210,7 +5209,7 @@ msgstr "Localización"
|
||||
#: pretix/base/models/orders.py:228 pretix/control/forms/filter.py:560
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:57
|
||||
msgid "Total amount"
|
||||
msgstr "Monto total"
|
||||
msgstr "Cantidad total"
|
||||
|
||||
#: pretix/base/models/orders.py:232 pretix/base/models/vouchers.py:292
|
||||
msgid ""
|
||||
@@ -5463,8 +5462,9 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/oauth/authorized.html:19
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html:6
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html:8
|
||||
#, fuzzy
|
||||
msgid "Organizers"
|
||||
msgstr "Organizadores"
|
||||
msgstr "Cuenta del organizador"
|
||||
|
||||
#: pretix/base/models/organizer.py:262
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html:35
|
||||
@@ -6283,10 +6283,11 @@ msgstr "No se encontraron respuestas coincidentes."
|
||||
|
||||
#: pretix/base/orderimport.py:740 pretix/base/services/cart.py:202
|
||||
#: pretix/base/services/orderimport.py:158
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"The seat you selected has already been taken. Please select a different seat."
|
||||
msgstr "Esta URL semántica ya está en uso. Por favor, elija una diferente."
|
||||
msgstr ""
|
||||
"El asiento que has seleccionado ya está ocupado. Por favor seleccione un "
|
||||
"asiento diferente."
|
||||
|
||||
#: pretix/base/orderimport.py:743 pretix/base/services/cart.py:199
|
||||
#, fuzzy
|
||||
@@ -7429,9 +7430,8 @@ msgstr ""
|
||||
"complemento de otro proyecto."
|
||||
|
||||
#: pretix/base/services/cart.py:200
|
||||
#, fuzzy
|
||||
msgid "Please select a valid seat."
|
||||
msgstr "Por favor, seleccione una cuota."
|
||||
msgstr "Por favor seleccione un asiento válido."
|
||||
|
||||
#: pretix/base/services/cart.py:201
|
||||
#, fuzzy
|
||||
@@ -10909,7 +10909,7 @@ msgstr "Srx."
|
||||
#: pretix/base/settings.py:3515 pretix/base/settings.py:3536
|
||||
#: pretix/base/settings.py:3558
|
||||
msgid "Given name"
|
||||
msgstr "Nombre dado"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: pretix/base/settings.py:3357 pretix/base/settings.py:3370
|
||||
#: pretix/base/settings.py:3386 pretix/base/settings.py:3402
|
||||
@@ -21649,9 +21649,8 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:87
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_profile.html:116
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_profile.html:171
|
||||
#, fuzzy
|
||||
msgid "Details"
|
||||
msgstr "Detalles del pedido"
|
||||
msgstr "Detalles"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:53
|
||||
#, fuzzy
|
||||
@@ -22775,7 +22774,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/pdf/index.html:141
|
||||
#: pretix/control/templates/pretixcontrol/pdf/index.html:173
|
||||
msgid "Loading…"
|
||||
msgstr "Cargando…"
|
||||
msgstr "Cargado…"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/pdf/index.html:144
|
||||
msgid "Start editing"
|
||||
@@ -26958,9 +26957,8 @@ msgid "Search text"
|
||||
msgstr "Buscar"
|
||||
|
||||
#: pretix/plugins/banktransfer/views.py:356
|
||||
#, fuzzy
|
||||
msgid "min"
|
||||
msgstr "Pie de imprenta"
|
||||
msgstr "Información de contacto"
|
||||
|
||||
#: pretix/plugins/banktransfer/views.py:357
|
||||
#, fuzzy
|
||||
@@ -29940,7 +29938,7 @@ msgstr "Contactar con el organizador del evento"
|
||||
#: pretix/presale/templates/pretixpresale/fragment_modals.html:129
|
||||
#: pretix/presale/templates/pretixpresale/organizers/base.html:91
|
||||
msgid "Privacy policy"
|
||||
msgstr ""
|
||||
msgstr "Aviso de Privacidad"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:176
|
||||
#: pretix/presale/templates/pretixpresale/organizers/base.html:94
|
||||
@@ -29951,7 +29949,7 @@ msgstr "Configuración de la factura"
|
||||
#: pretix/presale/templates/pretixpresale/event/base.html:179
|
||||
#: pretix/presale/templates/pretixpresale/organizers/base.html:97
|
||||
msgid "Imprint"
|
||||
msgstr "Pie de imprenta"
|
||||
msgstr "Información de contacto"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/checkout_addons.html:10
|
||||
msgid ""
|
||||
@@ -30007,9 +30005,8 @@ msgid "Cart expired"
|
||||
msgstr "El carrito de compras ha expirado"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/checkout_base.html:37
|
||||
#, fuzzy
|
||||
msgid "Show full cart"
|
||||
msgstr "Mostrar información"
|
||||
msgstr "Mostrar carrito completo"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/checkout_base.html:49
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:78
|
||||
|
||||
@@ -8,16 +8,16 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-18 07:26+0000\n"
|
||||
"PO-Revision-Date: 2021-11-25 21:00+0000\n"
|
||||
"Last-Translator: Ismael Menéndez Fernández <ismael.menendez@balidea.com>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
"js/es/>\n"
|
||||
"PO-Revision-Date: 2023-11-07 14:00+0000\n"
|
||||
"Last-Translator: Zona Vip <contacto@zonavip.mx>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/es/>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.8\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -52,7 +52,7 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:39
|
||||
msgid "Credit Card"
|
||||
msgstr ""
|
||||
msgstr "Tarjeta de crédito"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:40
|
||||
msgid "PayPal Pay Later"
|
||||
@@ -288,16 +288,12 @@ msgid "Ticket code revoked/changed"
|
||||
msgstr "Código de ticket revocado/cambiado"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:61
|
||||
#, fuzzy
|
||||
#| msgid "Ticket not paid"
|
||||
msgid "Ticket blocked"
|
||||
msgstr "Ticket por pagar"
|
||||
msgstr "Ticket bloqueado"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:62
|
||||
#, fuzzy
|
||||
#| msgid "Ticket not paid"
|
||||
msgid "Ticket not valid at this time"
|
||||
msgstr "Ticket por pagar"
|
||||
msgstr "Ticket no válido en este momento"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:63
|
||||
msgid "Order canceled"
|
||||
@@ -427,11 +423,11 @@ msgstr "Ver variaciones del producto"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:101
|
||||
msgid "Gate"
|
||||
msgstr ""
|
||||
msgstr "Puerta"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:105
|
||||
msgid "Current date and time"
|
||||
msgstr "Fecha y hora"
|
||||
msgstr "Fecha y hora actual"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:109
|
||||
msgid "Current day of the week (1 = Monday, 7 = Sunday)"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 12:47+0000\n"
|
||||
"PO-Revision-Date: 2022-09-15 21:00+0000\n"
|
||||
"Last-Translator: Svyatoslav <slava@digitalarthouse.eu>\n"
|
||||
"PO-Revision-Date: 2023-11-03 22:00+0000\n"
|
||||
"Last-Translator: Jāzeps Benjamins Baško <jazeps.basko@gmail.com>\n"
|
||||
"Language-Team: Latvian <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"lv/>\n"
|
||||
"Language: lv\n"
|
||||
@@ -18,7 +18,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n % 10 == 0 || n % 100 >= 11 && n % 100 <= "
|
||||
"19) ? 0 : ((n % 10 == 1 && n % 100 != 11) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 4.14\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -42,11 +42,11 @@ msgstr "Ķīniešu (vienkāršota)"
|
||||
|
||||
#: pretix/_base_settings.py:83
|
||||
msgid "Chinese (traditional)"
|
||||
msgstr ""
|
||||
msgstr "Ķīniešu (tradicionālā)"
|
||||
|
||||
#: pretix/_base_settings.py:84
|
||||
msgid "Czech"
|
||||
msgstr ""
|
||||
msgstr "Čehu"
|
||||
|
||||
#: pretix/_base_settings.py:85
|
||||
msgid "Danish"
|
||||
@@ -78,7 +78,7 @@ msgstr "Grieķu"
|
||||
|
||||
#: pretix/_base_settings.py:92
|
||||
msgid "Indonesian"
|
||||
msgstr ""
|
||||
msgstr "Indonēziešu"
|
||||
|
||||
#: pretix/_base_settings.py:93
|
||||
msgid "Italian"
|
||||
@@ -102,7 +102,7 @@ msgstr "Portugāļu (Brazīlija)"
|
||||
|
||||
#: pretix/_base_settings.py:98
|
||||
msgid "Romanian"
|
||||
msgstr ""
|
||||
msgstr "Rumāņu"
|
||||
|
||||
#: pretix/_base_settings.py:99
|
||||
msgid "Russian"
|
||||
@@ -118,7 +118,7 @@ msgstr "Turku"
|
||||
|
||||
#: pretix/_base_settings.py:102
|
||||
msgid "Ukrainian"
|
||||
msgstr ""
|
||||
msgstr "Ukraiņu"
|
||||
|
||||
#: pretix/api/auth/devicesecurity.py:31
|
||||
msgid ""
|
||||
@@ -300,10 +300,9 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/api/serializers/order.py:79
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Your input was not valid."
|
||||
#, python-brace-format
|
||||
msgid "\"{input}\" is not a valid choice."
|
||||
msgstr "Jūsu ievadītais teksts nav derīgs."
|
||||
msgstr "Jūsu ievadītais teksts \"{input}\" nav derīgs."
|
||||
|
||||
#: pretix/api/serializers/order.py:1297 pretix/api/views/cart.py:220
|
||||
#: pretix/base/services/orders.py:1495
|
||||
@@ -668,10 +667,9 @@ msgid "Incompatible SSO provider: \"{error}\"."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/customersso/oidc.py:109
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Your event registration: {code}"
|
||||
#, python-brace-format
|
||||
msgid "You are not requesting \"{scope}\"."
|
||||
msgstr "Jūsu pasākuma reģistrācija: {code}"
|
||||
msgstr "Jūs nepieprasāt \"{scope}\""
|
||||
|
||||
#: pretix/base/customersso/oidc.py:115
|
||||
#, python-brace-format
|
||||
@@ -1032,10 +1030,8 @@ msgstr "Pasākuma biļete {event}-{code}"
|
||||
#: pretix/plugins/reports/exporters.py:434
|
||||
#: pretix/plugins/reports/exporters.py:671
|
||||
#: pretix/plugins/ticketoutputpdf/exporters.py:85
|
||||
#, fuzzy
|
||||
#| msgid "Date and time"
|
||||
msgid "Date range"
|
||||
msgstr "Datums un laiks"
|
||||
msgstr "Datumu apgabals"
|
||||
|
||||
#: pretix/base/exporters/dekodi.py:223 pretix/base/exporters/invoices.py:77
|
||||
#, fuzzy
|
||||
@@ -2687,7 +2683,7 @@ msgstr ""
|
||||
#: pretix/plugins/reports/accountingreport.py:104
|
||||
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_list.html:67
|
||||
msgid "All"
|
||||
msgstr "Visi"
|
||||
msgstr "Viss"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1258 pretix/control/forms/filter.py:1317
|
||||
msgid "Live"
|
||||
@@ -3035,10 +3031,9 @@ msgid "Invalid placeholder(s): %(value)s"
|
||||
msgstr "Nederīgs (-i) vietturis (-i): %(value)s"
|
||||
|
||||
#: pretix/base/forms/widgets.py:67
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Sample city"
|
||||
#, python-format
|
||||
msgid "Sample: %s"
|
||||
msgstr "Piemēra pilsēta"
|
||||
msgstr "Piemērs: %s"
|
||||
|
||||
#: pretix/base/forms/widgets.py:70
|
||||
#, python-brace-format
|
||||
@@ -3200,11 +3195,10 @@ msgid "Single price: {net_price} net / {gross_price} gross"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoice.py:659
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Single price"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Single price: {price}"
|
||||
msgstr "Vienības cena"
|
||||
msgstr "Vienības cena: {price}"
|
||||
|
||||
#: pretix/base/invoice.py:677 pretix/base/invoice.py:683
|
||||
msgctxt "invoice"
|
||||
@@ -3256,32 +3250,24 @@ msgid "Included taxes"
|
||||
msgstr "Iekļautie nodokļi"
|
||||
|
||||
#: pretix/base/invoice.py:829
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgctxt "invoice"
|
||||
#| msgid ""
|
||||
#| "Using the conversion rate of 1:{rate} as published by the European "
|
||||
#| "Central Bank on {date}, this corresponds to:"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid ""
|
||||
"Using the conversion rate of 1:{rate} as published by the {authority} on "
|
||||
"{date}, this corresponds to:"
|
||||
msgstr ""
|
||||
"Izmantojot maiņas kursu 1:{rate}, ko Eiropas Centrālā banka publicēja "
|
||||
"{date}, šis atbilst:"
|
||||
"Izmantojot maiņas kursu 1:{rate}, ko {authority} publicēja {date}, šis "
|
||||
"atbilst:"
|
||||
|
||||
#: pretix/base/invoice.py:844
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgctxt "invoice"
|
||||
#| msgid ""
|
||||
#| "Using the conversion rate of 1:{rate} as published by the European "
|
||||
#| "Central Bank on {date}, the invoice total corresponds to {total}."
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid ""
|
||||
"Using the conversion rate of 1:{rate} as published by the {authority} on "
|
||||
"{date}, the invoice total corresponds to {total}."
|
||||
msgstr ""
|
||||
"Izmantojot maiņas kursu 1:{rate}, ko Eiropas Centrālā banka publicēja "
|
||||
"{date}, rēķina kopsumma atbilst {total}."
|
||||
"Izmantojot maiņas kursu 1:{rate}, ko {authority} publicēja {date}, rēķina "
|
||||
"kopsumma atbilst {total}."
|
||||
|
||||
#: pretix/base/invoice.py:858
|
||||
msgid "Modern Invoice Renderer (pretix 2.7)"
|
||||
@@ -4032,10 +4018,8 @@ msgid "Export"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/exports.py:59
|
||||
#, fuzzy
|
||||
#| msgid "Additional fee"
|
||||
msgid "Additional recipients"
|
||||
msgstr "Papildu maksa"
|
||||
msgstr "Papildu saņēmēji"
|
||||
|
||||
#: pretix/base/models/exports.py:61 pretix/base/models/exports.py:66
|
||||
#: pretix/base/models/exports.py:71
|
||||
@@ -4043,16 +4027,12 @@ msgid "You can specify multiple recipients separated by commas."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/exports.py:64
|
||||
#, fuzzy
|
||||
#| msgid "Additional fee"
|
||||
msgid "Additional recipients (Cc)"
|
||||
msgstr "Papildu maksa"
|
||||
msgstr "Papildu saņēmēji (cc)"
|
||||
|
||||
#: pretix/base/models/exports.py:69
|
||||
#, fuzzy
|
||||
#| msgid "Additional fee"
|
||||
msgid "Additional recipients (Bcc)"
|
||||
msgstr "Papildu maksa"
|
||||
msgstr "Papildu saņēmēji (Bcc)"
|
||||
|
||||
#: pretix/base/models/exports.py:74 pretix/control/forms/event.py:1070
|
||||
#: pretix/control/forms/event.py:1132 pretix/control/forms/event.py:1144
|
||||
@@ -7178,16 +7158,12 @@ msgstr[2] ""
|
||||
#: pretix/base/services/cart.py:134 pretix/base/services/orders.py:154
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:157
|
||||
#: pretix/presale/views/waiting.py:104 pretix/presale/views/widget.py:715
|
||||
#, fuzzy
|
||||
#| msgid "The presale period for this event has not yet started."
|
||||
msgid "The booking period for this event has not yet started."
|
||||
msgstr "Šī pasākuma iepriekšpārdošanas periods vēl nav sācies."
|
||||
msgstr "Šī pasākuma biļešu pārdošanas periods vēl nav sācies."
|
||||
|
||||
#: pretix/base/services/cart.py:135
|
||||
#, fuzzy
|
||||
#| msgid "The presale period for this event has ended."
|
||||
msgid "The booking period for this event has ended."
|
||||
msgstr "Šī pasākuma iepriekšpārdošanas periods ir beidzies."
|
||||
msgstr "Šī pasākuma biļešu pārdošanas periods ir beidzies."
|
||||
|
||||
#: pretix/base/services/cart.py:136
|
||||
msgid ""
|
||||
@@ -7196,28 +7172,20 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/cart.py:138
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "The presale period for this event has not yet started. The affected "
|
||||
#| "positions have been removed from your cart."
|
||||
msgid ""
|
||||
"The booking period for this event has not yet started. The affected "
|
||||
"positions have been removed from your cart."
|
||||
msgstr ""
|
||||
"Šī pasākuma iepriekšpārdošanas periods vēl nav sācies. Skartās pozīcijas ir "
|
||||
"Šī pasākuma biļešu pārdošanas periods vēl nav sācies. Skartās pozīcijas ir "
|
||||
"noņemtas no jūsu groza."
|
||||
|
||||
#: pretix/base/services/cart.py:141 pretix/base/services/orders.py:182
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "The presale period for one of the events in your cart has ended. The "
|
||||
#| "affected positions have been removed from your cart."
|
||||
msgid ""
|
||||
"The booking period for one of the events in your cart has ended. The "
|
||||
"affected positions have been removed from your cart."
|
||||
msgstr ""
|
||||
"Ir beidzies iepriekšpārdošanas periods vienam no jūsu grozā esošajiem "
|
||||
"pasākumiem. Skartās pozīcijas ir noņemtas no jūsu groza."
|
||||
"Ir beidzies biļešu pārdošanas periods vienam no jūsu grozā esošajiem "
|
||||
"pasākumiem. Skartās pozīcijas ir izņemtas no jūsu groza."
|
||||
|
||||
#: pretix/base/services/cart.py:143
|
||||
#, fuzzy
|
||||
@@ -7497,10 +7465,8 @@ msgid "number of entries before {datetime}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:307
|
||||
#, fuzzy
|
||||
#| msgid "Weekend day"
|
||||
msgid "week day"
|
||||
msgstr "Nedēļas nogales diena"
|
||||
msgstr "Nedēļas diena"
|
||||
|
||||
#: pretix/base/services/checkin.py:343 pretix/control/forms/filter.py:1130
|
||||
msgid "Monday"
|
||||
@@ -7558,17 +7524,14 @@ msgid "This ticket has been blocked."
|
||||
msgstr "Šī biļete jau ir izmantota."
|
||||
|
||||
#: pretix/base/services/checkin.py:882 pretix/base/services/checkin.py:886
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "This voucher is not valid for this event date."
|
||||
#, python-brace-format
|
||||
msgid "This ticket is only valid after {datetime}."
|
||||
msgstr "Šis kupons nav derīgs šajā pasākuma datumā."
|
||||
msgstr "Šis kupons ir derīgs tikai pēc {datetime}."
|
||||
|
||||
#: pretix/base/services/checkin.py:896 pretix/base/services/checkin.py:900
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "This ticket has already been redeemed."
|
||||
#, python-brace-format
|
||||
msgid "This ticket was only valid before {datetime}."
|
||||
msgstr "Šī biļete jau ir izmantota."
|
||||
msgstr "Šī biļete bija derīga tika līdz {datetime}."
|
||||
|
||||
#: pretix/base/services/checkin.py:931
|
||||
msgid "This order position has an invalid product for this check-in list."
|
||||
@@ -7865,10 +7828,8 @@ msgstr[2] ""
|
||||
"no jūsu groza noņēmām liekos vienumus."
|
||||
|
||||
#: pretix/base/services/orders.py:155
|
||||
#, fuzzy
|
||||
#| msgid "The presale period has ended."
|
||||
msgid "The booking period has ended."
|
||||
msgstr "Iepriekšpārdošanas periods ir beidzies."
|
||||
msgstr "Biļešu pārdošanas periods ir beidzies."
|
||||
|
||||
#: pretix/base/services/orders.py:161
|
||||
msgid ""
|
||||
@@ -7918,16 +7879,12 @@ msgstr ""
|
||||
"kods."
|
||||
|
||||
#: pretix/base/services/orders.py:178
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "The presale period for one of the events in your cart has not yet "
|
||||
#| "started. The affected positions have been removed from your cart."
|
||||
msgid ""
|
||||
"The booking period for one of the events in your cart has not yet started. "
|
||||
"The affected positions have been removed from your cart."
|
||||
msgstr ""
|
||||
"Vienam no jūsu grozā esošajiem pasākumiem vēl nav sācies pārdošanas laika "
|
||||
"posms. Skartās pozīcijas ir noņemtas no jūsu groza."
|
||||
"Vienam no jūsu grozā esošajiem pasākumiem vēl nav sācies biļešu pārdošanas "
|
||||
"periods. Skartās pozīcijas ir izņemtas no jūsu groza."
|
||||
|
||||
#: pretix/base/services/orders.py:185
|
||||
msgid ""
|
||||
@@ -7946,16 +7903,11 @@ msgstr ""
|
||||
"sēdvietām, tāpēc mēs noņēmām pozīciju no jūsu groza."
|
||||
|
||||
#: pretix/base/services/orders.py:202
|
||||
#, fuzzy, python-format
|
||||
#| msgid ""
|
||||
#| "This order can not be canceled since the gift card {card} purchased in "
|
||||
#| "this order has already been redeemed."
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot remove the position %(addon)s since it has already been checked "
|
||||
"in."
|
||||
msgstr ""
|
||||
"Šo pasūtījumu nevar atcelt, jo dāvanu karte {card}, kas iegādāta šajā "
|
||||
"pasūtījumā, jau ir izmantota."
|
||||
msgstr "Pozīciju %(addon)s nevar atcelt, jo tas jau ir iečekots."
|
||||
|
||||
#: pretix/base/services/orders.py:218
|
||||
#, fuzzy
|
||||
@@ -8567,10 +8519,9 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py:682 pretix/base/settings.py:704
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Please do not use special characters in names."
|
||||
#, python-brace-format
|
||||
msgid "Please only use the characters {allowed} in this field."
|
||||
msgstr "Lūdzu neizmantojiet speciālās rakstzīmes vārdos."
|
||||
msgstr "Lūdzu izmantojiet tikai atļautās rakstzīmes ({allowed})."
|
||||
|
||||
#: pretix/base/settings.py:695
|
||||
msgid "Invoice number prefix for cancellations"
|
||||
@@ -8747,7 +8698,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py:996
|
||||
msgid "Accept late payments"
|
||||
msgstr ""
|
||||
msgstr "Pieņemt kavētus maksājumus"
|
||||
|
||||
#: pretix/base/settings.py:997
|
||||
msgid ""
|
||||
@@ -9963,7 +9914,7 @@ msgstr ""
|
||||
"\n"
|
||||
"{voucher_list}\n"
|
||||
"\n"
|
||||
"Jūs tos variet izmantot mūsu biļešu e-veikalā:\n"
|
||||
"Jūs tos varat izmantot mūsu biļešu e-veikalā:\n"
|
||||
"\n"
|
||||
"{url}\n"
|
||||
"\n"
|
||||
@@ -10063,7 +10014,7 @@ msgstr ""
|
||||
"\n"
|
||||
"{voucher_list}\n"
|
||||
"\n"
|
||||
"Jūs tos variet izmantot mūsu biļešu e-veikalā:\n"
|
||||
"Jūs tos varat izmantot mūsu biļešu e-veikalā:\n"
|
||||
"\n"
|
||||
"{url}\n"
|
||||
"\n"
|
||||
@@ -10799,7 +10750,7 @@ msgstr "Jums nav piekļuves šai lapai."
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_start.html:4
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_start.html:6
|
||||
msgid "Admin mode"
|
||||
msgstr ""
|
||||
msgstr "Admin režīms"
|
||||
|
||||
#: pretix/base/templates/404.html:4 pretix/base/templates/404.html:8
|
||||
msgid "Not found"
|
||||
@@ -10860,7 +10811,7 @@ msgstr ""
|
||||
#: pretix/base/templates/pretixbase/email/email_footer.html:3
|
||||
#, python-format
|
||||
msgid "powered by <a %(a_attr)s>pretix</a>"
|
||||
msgstr ""
|
||||
msgstr "darbina <a %(a_attr)s>pretix</a>"
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/export_failed.txt:2
|
||||
#, fuzzy
|
||||
@@ -10869,10 +10820,8 @@ msgid "Your export failed."
|
||||
msgstr "Exportētie faili"
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/export_failed.txt:4
|
||||
#, fuzzy
|
||||
#| msgid "Refund reason"
|
||||
msgid "Reason:"
|
||||
msgstr "Naudas atmaksāšanas iemesls"
|
||||
msgstr "Iemesls:"
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/export_failed.txt:7
|
||||
msgid "If your export fails five times in a row, it will no longer be sent."
|
||||
@@ -12400,7 +12349,7 @@ msgstr "Sākuma datums līdz"
|
||||
#: pretix/control/forms/filter.py:1888 pretix/control/forms/filter.py:1891
|
||||
#: pretix/control/templates/pretixcontrol/users/index.html:52
|
||||
msgid "Administrator"
|
||||
msgstr ""
|
||||
msgstr "Administrators"
|
||||
|
||||
#: pretix/control/forms/filter.py:1892
|
||||
msgid "No administrator"
|
||||
@@ -12547,7 +12496,7 @@ msgstr "Deaktivizētās ierīces"
|
||||
|
||||
#: pretix/control/forms/global_settings.py:60
|
||||
msgid "Additional footer text"
|
||||
msgstr "Papildus lapas galvenes (footer) teksts"
|
||||
msgstr "Papildu teksts kājenei"
|
||||
|
||||
#: pretix/control/forms/global_settings.py:61
|
||||
msgid "Will be included as additional text in the footer, site-wide."
|
||||
@@ -15293,7 +15242,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/user/history.html:10
|
||||
#: pretix/control/templates/pretixcontrol/user/settings.html:70
|
||||
msgid "Account history"
|
||||
msgstr ""
|
||||
msgstr "Konta vēsture"
|
||||
|
||||
#: pretix/control/navigation.py:415
|
||||
msgid "All users"
|
||||
@@ -15303,7 +15252,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html:5
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html:7
|
||||
msgid "Admin sessions"
|
||||
msgstr ""
|
||||
msgstr "Admin sesijas"
|
||||
|
||||
#: pretix/control/navigation.py:427
|
||||
#: pretix/control/templates/pretixcontrol/global_settings_base.html:5
|
||||
@@ -15390,7 +15339,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/auth/invite.html:7
|
||||
msgid "Accept an invitation"
|
||||
msgstr ""
|
||||
msgstr "Pieņemt ielūgumu"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/auth/invite.html:10
|
||||
#, python-format
|
||||
@@ -15654,7 +15603,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/base.html:373
|
||||
msgid "Read more"
|
||||
msgstr ""
|
||||
msgstr "Lasīt vairāk"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/base.html:390
|
||||
msgid ""
|
||||
@@ -16353,7 +16302,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:15
|
||||
msgid "Your upcoming events"
|
||||
msgstr ""
|
||||
msgstr "Jūsu gaidāmie pasākumi"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:20
|
||||
#: pretix/control/templates/pretixcontrol/events/create_base.html:4
|
||||
@@ -16367,7 +16316,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:39
|
||||
msgid "View all upcoming events"
|
||||
msgstr ""
|
||||
msgstr "Skatīt visus gaidāmos pasākumus"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:44
|
||||
msgid "Your most recent events"
|
||||
@@ -16375,7 +16324,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:60
|
||||
msgid "View all recent events"
|
||||
msgstr ""
|
||||
msgstr "Skatīt visus nesenos pasākumus"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:65
|
||||
msgid "Your event series"
|
||||
@@ -16387,7 +16336,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/dashboard.html:86
|
||||
msgid "Other features"
|
||||
msgstr ""
|
||||
msgstr "Citas iespējas"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/email_setup.txt:1
|
||||
#, python-format
|
||||
@@ -16421,6 +16370,15 @@ msgid ""
|
||||
"Best regards, \n"
|
||||
"Your pretix team\n"
|
||||
msgstr ""
|
||||
"Sveicināti!\n"
|
||||
"\n"
|
||||
"Jūs pieprasījāt paroles maiņu. Lūdzu, dodieties uz šo lapu, lai atstatītu "
|
||||
"paroli:\n"
|
||||
"\n"
|
||||
"%(url)s\n"
|
||||
"\n"
|
||||
"Ar cieņu\n"
|
||||
"pretix komanda\n"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/invitation.txt:1
|
||||
#, python-format
|
||||
@@ -16898,7 +16856,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/invoicing.html:26
|
||||
msgid "Address form"
|
||||
msgstr ""
|
||||
msgstr "Adreses forma"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/invoicing.html:38
|
||||
msgid "Issuer details"
|
||||
@@ -18292,7 +18250,7 @@ msgstr "Jauns variants"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/item/include_variations.html:215
|
||||
msgid "Add a new variation"
|
||||
msgstr ""
|
||||
msgstr "Pievienot jaunu variāciju"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/item/index.html:153
|
||||
msgid "Availability"
|
||||
@@ -18449,13 +18407,11 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/discount_delete.html:21
|
||||
#, fuzzy, python-format
|
||||
#| msgid ""
|
||||
#| "Are you sure you want to delete the rule <strong>%(subject)s</strong>?"
|
||||
#, python-format
|
||||
msgid "Are you sure you want to delete the discount <strong>%(name)s</strong>?"
|
||||
msgstr ""
|
||||
"Vai esat pārliecināts/-a, ka vēlaties dzēst noteikumu <strong>%(subject)s</"
|
||||
"strong>?"
|
||||
"Vai esat pārliecināts/-a, ka vēlaties dzēst atlaidi "
|
||||
"<strong>%(name)s</strong>?"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/discount_delete.html:25
|
||||
#, python-format
|
||||
@@ -19472,10 +19428,9 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html:450
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:107
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Admission: %(datetime)s"
|
||||
#, python-format
|
||||
msgid "Valid %(datetime_range)s"
|
||||
msgstr "Ieeja: %(datetime)s"
|
||||
msgstr "Korekts %(datetime_range)s"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html:496
|
||||
msgid "Ticket page"
|
||||
@@ -20452,7 +20407,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html:74
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
msgstr "Darbības"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/orders/search.html:7
|
||||
#: pretix/control/templates/pretixcontrol/orders/search.html:9
|
||||
@@ -20969,10 +20924,8 @@ msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard_acceptance_list.html:66
|
||||
#, fuzzy
|
||||
#| msgid "Accept anyway"
|
||||
msgid "Accept"
|
||||
msgstr "Piekrist tik un tā"
|
||||
msgstr "Piekrist"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard_acceptance_list.html:69
|
||||
msgid "Decline"
|
||||
@@ -21324,7 +21277,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/team_members.html:81
|
||||
#: pretix/control/templates/pretixcontrol/organizers/team_members.html:122
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
msgstr "Pievienot"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/team_members.html:88
|
||||
msgid "API tokens"
|
||||
@@ -29606,17 +29559,14 @@ msgstr "Citi datumi"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:142
|
||||
#: pretix/presale/views/waiting.py:100 pretix/presale/views/widget.py:708
|
||||
#, fuzzy
|
||||
#| msgid "The presale period for this event is over."
|
||||
msgid "The booking period for this event is over."
|
||||
msgstr "Šī pasākuma iepriekšpārdošanas periods ir beidzies."
|
||||
msgstr "Pasākuma biļešu pārdošanas periods ir beidzies."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:150
|
||||
#: pretix/presale/views/widget.py:710
|
||||
#, fuzzy, python-format
|
||||
#| msgid "The presale for this event will start on %(date)s at %(time)s."
|
||||
#, python-format
|
||||
msgid "The booking period for this event will start on %(date)s at %(time)s."
|
||||
msgstr "Šī pasākuma iepriekšpārdošana sāksies %(date)s plkst. %(time)s."
|
||||
msgstr "Šī pasākuma biļešu pārdošanas periods sāksies %(date)s plkst. %(time)s."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:172
|
||||
#: pretix/presale/templates/pretixpresale/event/seatingplan.html:23
|
||||
@@ -30614,7 +30564,7 @@ msgstr "Netika atrasti publiski gaidāmi pasākumi."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html:143
|
||||
msgid "Show past events"
|
||||
msgstr "Rādīt pagātnes pasākumus"
|
||||
msgstr "Rādīt jau notikušus pasākumus"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/pagination.html:14
|
||||
#, python-format
|
||||
@@ -30687,10 +30637,8 @@ msgid "Your cart is empty"
|
||||
msgstr "Jūsu grozs ir tukšs"
|
||||
|
||||
#: pretix/presale/views/checkout.py:59
|
||||
#, fuzzy
|
||||
#| msgid "The presale for this event is over or has not yet started."
|
||||
msgid "The booking period for this event is over or has not yet started."
|
||||
msgstr "Šī pasākuma iepriekšpārdošana ir beigusies vai vēl nav sākusies."
|
||||
msgstr "Šī pasākuma biļešu pārdošanas periods ir beidzies vai vēl nav sācies."
|
||||
|
||||
#: pretix/presale/views/customer.py:247
|
||||
msgid ""
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-18 07:26+0000\n"
|
||||
"PO-Revision-Date: 2022-06-20 02:00+0000\n"
|
||||
"PO-Revision-Date: 2023-11-02 13:02+0000\n"
|
||||
"Last-Translator: fyksen <fredrik@fyksen.me>\n"
|
||||
"Language-Team: Norwegian Bokmål <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/nb_NO/>\n"
|
||||
@@ -17,13 +17,13 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.12.2\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:68
|
||||
msgid "Marked as paid"
|
||||
msgstr "Sett som betalt"
|
||||
msgstr "Merkert som betalt"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:76
|
||||
msgid "Comment:"
|
||||
@@ -209,7 +209,7 @@ msgstr "Inngang"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:39
|
||||
msgid "Exit"
|
||||
msgstr "Utgang"
|
||||
msgstr "Avslutt"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:40
|
||||
msgid "Scan a ticket or search and press return…"
|
||||
@@ -230,11 +230,11 @@ msgstr "Ubetalt"
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:44
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:45
|
||||
msgid "Canceled"
|
||||
msgstr "Kansellert"
|
||||
msgstr "Avlyst"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:46
|
||||
msgid "Redeemed"
|
||||
msgstr "Løst inn"
|
||||
msgstr "Innløst"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:47
|
||||
msgid "Cancel"
|
||||
@@ -243,7 +243,7 @@ msgstr "Avbryt"
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:49
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
||||
msgid "Ticket not paid"
|
||||
msgstr "Billett ikke betalt"
|
||||
msgstr "Billetten er ikke betalt."
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:50
|
||||
msgid "This ticket is not yet paid. Do you want to continue anyways?"
|
||||
@@ -251,7 +251,7 @@ msgstr "Denne billetten er ikke betalt. Vil du fortsette likevel?"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:51
|
||||
msgid "Additional information required"
|
||||
msgstr "Ekstra informasjon kreves"
|
||||
msgstr "pretix account invitation"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:52
|
||||
msgid "Valid ticket"
|
||||
@@ -263,11 +263,11 @@ msgstr "Utgang registrert"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:54
|
||||
msgid "Ticket already used"
|
||||
msgstr "Billett allerede benyttet"
|
||||
msgstr "Billetten er allerede brukt."
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:55
|
||||
msgid "Information required"
|
||||
msgstr "Informasjon trengs"
|
||||
msgstr "Informasjon påkrevd"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:56
|
||||
msgid "Unknown ticket"
|
||||
@@ -286,16 +286,12 @@ msgid "Ticket code revoked/changed"
|
||||
msgstr "Billettkode tilbakekalt/endret"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:61
|
||||
#, fuzzy
|
||||
#| msgid "Ticket not paid"
|
||||
msgid "Ticket blocked"
|
||||
msgstr "Billett ikke betalt"
|
||||
msgstr "Billett blokkert"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:62
|
||||
#, fuzzy
|
||||
#| msgid "Ticket not paid"
|
||||
msgid "Ticket not valid at this time"
|
||||
msgstr "Billett ikke betalt"
|
||||
msgstr "Billetten er ikke gyldig på dette tidspunktet"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:63
|
||||
msgid "Order canceled"
|
||||
@@ -303,7 +299,7 @@ msgstr "Ordre kansellert"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:64
|
||||
msgid "Ticket code is ambiguous on list"
|
||||
msgstr ""
|
||||
msgstr "Billettkoden er tvetydig på listen"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:65
|
||||
msgid "Checked-in Tickets"
|
||||
@@ -423,7 +419,7 @@ msgstr "Produkt variasjon"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:101
|
||||
msgid "Gate"
|
||||
msgstr ""
|
||||
msgstr "Port"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:105
|
||||
msgid "Current date and time"
|
||||
@@ -442,16 +438,12 @@ msgid "Number of previous entries since midnight"
|
||||
msgstr "Antall tidligere oppføringer siden midnatt"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:121
|
||||
#, fuzzy
|
||||
#| msgid "Number of previous entries"
|
||||
msgid "Number of previous entries since"
|
||||
msgstr "Antall tidligere oppføringer"
|
||||
msgstr "Antall tidligere oppføringer siden"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:125
|
||||
#, fuzzy
|
||||
#| msgid "Number of previous entries"
|
||||
msgid "Number of previous entries before"
|
||||
msgstr "Antall tidligere oppføringer"
|
||||
msgstr "Antall tidligere oppføringer før"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:129
|
||||
msgid "Number of days with a previous entry"
|
||||
@@ -507,7 +499,7 @@ msgstr "minutter"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:174
|
||||
msgid "Duplicate"
|
||||
msgstr ""
|
||||
msgstr "Duplikat"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/editor.js:72
|
||||
msgid "Check-in QR"
|
||||
@@ -689,44 +681,39 @@ msgid "Your local time:"
|
||||
msgstr "Din lokale tid:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/walletdetection.js:39
|
||||
#, fuzzy
|
||||
#| msgid "Apple Pay"
|
||||
msgid "Google Pay"
|
||||
msgstr "Apple Pay"
|
||||
msgstr "Google Pay"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:16
|
||||
msgctxt "widget"
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
msgstr "Antall"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:17
|
||||
msgctxt "widget"
|
||||
msgid "Decrease quantity"
|
||||
msgstr ""
|
||||
msgstr "Begrenset antall"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:18
|
||||
msgctxt "widget"
|
||||
msgid "Increase quantity"
|
||||
msgstr ""
|
||||
msgstr "Øk antall"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:19
|
||||
msgctxt "widget"
|
||||
msgid "Price"
|
||||
msgstr ""
|
||||
msgstr "Pris"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
||||
#, fuzzy
|
||||
#| msgid "Selected only"
|
||||
msgctxt "widget"
|
||||
msgid "Select"
|
||||
msgstr "Kun valgte"
|
||||
msgstr "Velg"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||
#, fuzzy, javascript-format
|
||||
#| msgid "Selected only"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Select %s"
|
||||
msgstr "Kun valgte"
|
||||
msgstr "Velg%s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||
#, fuzzy, javascript-format
|
||||
@@ -937,6 +924,9 @@ msgid ""
|
||||
"add yourself to the waiting list. We will then notify if seats are available "
|
||||
"again."
|
||||
msgstr ""
|
||||
"Noen eller alle billettkategorier er for øyeblikket utsolgt. Hvis du ønsker, "
|
||||
"kan du legge deg til på ventelisten. Vi vil da gi deg beskjed hvis det blir "
|
||||
"ledige seter igjen."
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
||||
msgctxt "widget"
|
||||
|
||||
@@ -7,16 +7,16 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 12:47+0000\n"
|
||||
"PO-Revision-Date: 2023-08-25 04:00+0000\n"
|
||||
"Last-Translator: Alain <alain@waag.org>\n"
|
||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/"
|
||||
">\n"
|
||||
"PO-Revision-Date: 2023-11-10 00:00+0000\n"
|
||||
"Last-Translator: Thomas Vranken <thvranken@gmail.com>\n"
|
||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/>"
|
||||
"\n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.18.2\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -32506,6 +32506,10 @@ msgid ""
|
||||
"email addresses. There is no guarantee that you will receive a certain "
|
||||
"number of tickets."
|
||||
msgstr ""
|
||||
"Houd er rekening mee dat u slechts één ticket ontvangt. Als u meerdere "
|
||||
"tickets nodig heeft, moet u uzelf meerdere keren met verschillende e-"
|
||||
"mailadressen aan de wachtlijst toevoegen. Er is geen garantie dat u een "
|
||||
"bepaald aantal tickets ontvangt."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/waitinglist.html:39
|
||||
msgid "Add me to the list"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 12:47+0000\n"
|
||||
"PO-Revision-Date: 2023-07-04 06:00+0000\n"
|
||||
"Last-Translator: Maciej Szymczak <maciej+github@szymczak.at>\n"
|
||||
"PO-Revision-Date: 2023-11-12 13:26+0000\n"
|
||||
"Last-Translator: Fast128 <fast128@post.pl>\n"
|
||||
"Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix/pl/"
|
||||
">\n"
|
||||
"Language: pl\n"
|
||||
@@ -18,7 +18,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 4.17\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -78,7 +78,7 @@ msgstr "Grecki"
|
||||
|
||||
#: pretix/_base_settings.py:92
|
||||
msgid "Indonesian"
|
||||
msgstr ""
|
||||
msgstr "Indonezyjski"
|
||||
|
||||
#: pretix/_base_settings.py:93
|
||||
msgid "Italian"
|
||||
@@ -333,10 +333,8 @@ msgstr ""
|
||||
|
||||
#: pretix/api/serializers/organizer.py:102
|
||||
#: pretix/control/forms/organizer.py:798 pretix/presale/forms/customer.py:439
|
||||
#, fuzzy
|
||||
#| msgid "A voucher with this code already exists."
|
||||
msgid "An account with this email address is already registered."
|
||||
msgstr "Voucher o tym kodzie już istnieje."
|
||||
msgstr "Konto o tym adresie e-mail już istnieje."
|
||||
|
||||
#: pretix/api/serializers/organizer.py:205
|
||||
#: pretix/control/forms/organizer.py:647
|
||||
@@ -551,23 +549,16 @@ msgid "Waiting list entry received voucher"
|
||||
msgstr "Osoba z listy oczekujących dostała voucher"
|
||||
|
||||
#: pretix/api/webhooks.py:370
|
||||
#, fuzzy
|
||||
#| msgctxt "refund_source"
|
||||
#| msgid "Customer"
|
||||
msgid "Customer account created"
|
||||
msgstr "Klient"
|
||||
msgstr "Stworzono konto użytkownika"
|
||||
|
||||
#: pretix/api/webhooks.py:374
|
||||
#, fuzzy
|
||||
#| msgid "Account information changed"
|
||||
msgid "Customer account changed"
|
||||
msgstr "Zmiana informacji konta"
|
||||
msgstr "Zmieniono konto użytkownika"
|
||||
|
||||
#: pretix/api/webhooks.py:378
|
||||
#, fuzzy
|
||||
#| msgid "This product can only be bought using a voucher."
|
||||
msgid "Customer account anonymized"
|
||||
msgstr "Produkt może być kupiony tylko przy użyciu vouchera."
|
||||
msgstr "Konto użytkownika zanonimizowane"
|
||||
|
||||
#: pretix/base/addressvalidation.py:100 pretix/base/addressvalidation.py:103
|
||||
#: pretix/base/addressvalidation.py:108 pretix/base/forms/questions.py:934
|
||||
@@ -2947,7 +2938,7 @@ msgstr "Wprowadzone obecne hasło jest nieprawidłowe."
|
||||
|
||||
#: pretix/base/forms/user.py:58
|
||||
msgid "Please choose a password different to your current one."
|
||||
msgstr ""
|
||||
msgstr "Nowe hasło nie może być identyczne jak obecne."
|
||||
|
||||
#: pretix/base/forms/user.py:63 pretix/presale/forms/customer.py:373
|
||||
#: pretix/presale/forms/customer.py:442
|
||||
@@ -2989,10 +2980,8 @@ msgid "Smartphone with the Authenticator application"
|
||||
msgstr "Smartfon z aplikacją Authenticator"
|
||||
|
||||
#: pretix/base/forms/user.py:178
|
||||
#, fuzzy
|
||||
#| msgid "U2F-compatible hardware token (e.g. Yubikey)"
|
||||
msgid "WebAuthn-compatible hardware token (e.g. Yubikey)"
|
||||
msgstr "Token hardware'owy kompatybilny z U2F (np. Yubikey)"
|
||||
msgstr "Token hardware'owy kompatybilny z WebAuthn (np. Yubikey)"
|
||||
|
||||
#: pretix/base/forms/validators.py:62
|
||||
msgid ""
|
||||
@@ -3013,14 +3002,11 @@ msgid "Sample: %s"
|
||||
msgstr "Przedsprzedaż nierozpoczęta"
|
||||
|
||||
#: pretix/base/forms/widgets.py:70
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Invalid placeholder(s): %(value)s"
|
||||
#, python-brace-format
|
||||
msgid "Available placeholders: {list}"
|
||||
msgstr "Nieprawidłowy(e) symbol(e) zastępstwa: %(value)s"
|
||||
msgstr "Dostępne symbole zastępstwa: {list}"
|
||||
|
||||
#: pretix/base/forms/widgets.py:230 pretix/base/forms/widgets.py:235
|
||||
#, fuzzy
|
||||
#| msgid "Business customer"
|
||||
msgid "Business or institutional customer"
|
||||
msgstr "Klient firmowy"
|
||||
|
||||
@@ -3112,12 +3098,9 @@ msgid "Customer reference: {reference}"
|
||||
msgstr "Adnotacja klienta: {reference}"
|
||||
|
||||
#: pretix/base/invoice.py:568
|
||||
#, fuzzy
|
||||
#| msgctxt "refund_source"
|
||||
#| msgid "Customer"
|
||||
msgctxt "invoice"
|
||||
msgid "Customer VAT ID"
|
||||
msgstr "Klient"
|
||||
msgstr "Numer NIP Klienta"
|
||||
|
||||
#: pretix/base/invoice.py:575
|
||||
msgctxt "invoice"
|
||||
@@ -3125,11 +3108,9 @@ msgid "Beneficiary"
|
||||
msgstr "Beneficjent"
|
||||
|
||||
#: pretix/base/invoice.py:596
|
||||
#, fuzzy
|
||||
#| msgid "Invoice"
|
||||
msgctxt "invoice"
|
||||
msgid "Tax Invoice"
|
||||
msgstr "Faktura"
|
||||
msgstr "Faktura VAT"
|
||||
|
||||
#: pretix/base/invoice.py:597
|
||||
msgctxt "invoice"
|
||||
@@ -3177,14 +3158,13 @@ msgstr "Wartość"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Single price: {net_price} net / {gross_price} gross"
|
||||
msgstr ""
|
||||
msgstr "Cena jednostkowa: {net_price} netto / {gross_price} brutto"
|
||||
|
||||
#: pretix/base/invoice.py:659
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Original price"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Single price: {price}"
|
||||
msgstr "Cena oryginalna"
|
||||
msgstr "Cena jednostkowa: {price}"
|
||||
|
||||
#: pretix/base/invoice.py:677 pretix/base/invoice.py:683
|
||||
msgctxt "invoice"
|
||||
@@ -3192,30 +3172,24 @@ msgid "Invoice total"
|
||||
msgstr "Razem"
|
||||
|
||||
#: pretix/base/invoice.py:693
|
||||
#, fuzzy
|
||||
#| msgid "Only successful payments"
|
||||
msgctxt "invoice"
|
||||
msgid "Received payments"
|
||||
msgstr "Tylko pomyślne płatności"
|
||||
msgstr "Otrzymane płatności"
|
||||
|
||||
#: pretix/base/invoice.py:698
|
||||
msgctxt "invoice"
|
||||
msgid "Outstanding payments"
|
||||
msgstr ""
|
||||
msgstr "Zaległe płatności"
|
||||
|
||||
#: pretix/base/invoice.py:715
|
||||
#, fuzzy
|
||||
#| msgid "Gift card"
|
||||
msgctxt "invoice"
|
||||
msgid "Paid by gift card"
|
||||
msgstr "Karta prezentowa"
|
||||
msgstr "Zapłacono kartą prezentową"
|
||||
|
||||
#: pretix/base/invoice.py:720
|
||||
#, fuzzy
|
||||
#| msgid "Question option"
|
||||
msgctxt "invoice"
|
||||
msgid "Remaining amount"
|
||||
msgstr "Opcja pytania"
|
||||
msgstr "Pozostała kwota"
|
||||
|
||||
#: pretix/base/invoice.py:769
|
||||
msgctxt "invoice"
|
||||
@@ -3266,11 +3240,8 @@ msgstr ""
|
||||
"Centrylny w dniu {date}, suma faktury wynosi: {total}.."
|
||||
|
||||
#: pretix/base/invoice.py:858
|
||||
#, fuzzy
|
||||
#| msgctxt "invoice"
|
||||
#| msgid "Classic renderer (pretix 1.0)"
|
||||
msgid "Modern Invoice Renderer (pretix 2.7)"
|
||||
msgstr "Klasyczny renderer (pretix 1.0)"
|
||||
msgstr "Modern Invoice Renderer (pretix 2.7)"
|
||||
|
||||
#: pretix/base/invoice.py:947
|
||||
#, fuzzy
|
||||
@@ -3281,12 +3252,12 @@ msgstr "Proszę wpisać to samo hasło dwukrotnie"
|
||||
|
||||
#: pretix/base/media.py:61
|
||||
msgid "Barcode / QR-Code"
|
||||
msgstr ""
|
||||
msgstr "Kod kreskowy / Kod QR"
|
||||
|
||||
#: pretix/base/media.py:77
|
||||
#: pretix/control/templates/pretixcontrol/organizers/edit.html:237
|
||||
msgid "NFC UID-based"
|
||||
msgstr ""
|
||||
msgstr "NFC na bazie UID"
|
||||
|
||||
#: pretix/base/migrations/0077_auto_20171124_1629.py:33
|
||||
#: pretix/base/migrations/0077_auto_20171124_1629_squashed_0088_auto_20180328_1217.py:35
|
||||
@@ -3306,10 +3277,8 @@ msgid "Date joined"
|
||||
msgstr "Data dołączenia"
|
||||
|
||||
#: pretix/base/models/auth.py:256
|
||||
#, fuzzy
|
||||
#| msgid "Repeat new password"
|
||||
msgid "Force user to select a new password"
|
||||
msgstr "Powtórz nowe hasło"
|
||||
msgstr "Wymuś wybranie nowego hasła użytkownika"
|
||||
|
||||
#: pretix/base/models/auth.py:266
|
||||
msgid "Two-factor authentication is required to log in"
|
||||
@@ -3321,7 +3290,7 @@ msgstr "Powiadomienia według ustwień poniżej"
|
||||
|
||||
#: pretix/base/models/auth.py:271
|
||||
msgid "If turned off, you will not get any notifications."
|
||||
msgstr "Jeśli wyłączone, nie będą miały miejsca żadne powiadomienia"
|
||||
msgstr "Jeśli wyłączone, nie będą miały miejsca żadne powiadomienia."
|
||||
|
||||
#: pretix/base/models/auth.py:285
|
||||
#: pretix/control/templates/pretixcontrol/orders/bulk_action.html:23
|
||||
@@ -3369,18 +3338,20 @@ msgstr ""
|
||||
#: pretix/base/models/checkin.py:66
|
||||
msgctxt "checkin"
|
||||
msgid "Ignore check-ins on this list in statistics"
|
||||
msgstr ""
|
||||
msgstr "Ignoruj zameldowania obecne na tej liście w statystykach"
|
||||
|
||||
#: pretix/base/models/checkin.py:70
|
||||
msgctxt "checkin"
|
||||
msgid "Tickets with a check-in on this list should be considered \"used\""
|
||||
msgstr ""
|
||||
msgstr "Zameldowane bilety z tej listy powinny być uważane za \"użyte\""
|
||||
|
||||
#: pretix/base/models/checkin.py:71
|
||||
msgid ""
|
||||
"This is relevant in various situations, e.g. for deciding if a ticket can "
|
||||
"still be canceled by the customer."
|
||||
msgstr ""
|
||||
"To istotne w wielu sytuacjach, np żeby zdecydować czy bilet może być "
|
||||
"anulowany przez klienta."
|
||||
|
||||
#: pretix/base/models/checkin.py:75
|
||||
msgctxt "checkin"
|
||||
@@ -3399,6 +3370,7 @@ msgstr ""
|
||||
#: pretix/base/models/checkin.py:80
|
||||
msgid "Allow checking in add-on tickets by scanning the main ticket"
|
||||
msgstr ""
|
||||
"Pozwól na zameldowanie dodatkowych biletów przez skanowanie głównego biletu"
|
||||
|
||||
#: pretix/base/models/checkin.py:82
|
||||
msgid ""
|
||||
@@ -3410,36 +3382,37 @@ msgstr ""
|
||||
#: pretix/base/models/checkin.py:86 pretix/control/navigation.py:626
|
||||
#: pretix/control/templates/pretixcontrol/organizers/gates.html:5
|
||||
msgid "Gates"
|
||||
msgstr ""
|
||||
msgstr "Bramki"
|
||||
|
||||
#: pretix/base/models/checkin.py:87
|
||||
msgid ""
|
||||
"Does not have any effect for the validation of tickets, only for the "
|
||||
"automatic configuration of check-in devices."
|
||||
msgstr ""
|
||||
"Nie wpływa na sprawdzenie ważności biletu, tylko na automatyczną "
|
||||
"konfigurację urządzeń do sprawdzania biletów."
|
||||
|
||||
#: pretix/base/models/checkin.py:91
|
||||
msgid "Allow re-entering after an exit scan"
|
||||
msgstr ""
|
||||
msgstr "Pozwól na ponowne wejście bo zeskanowaniu na wyjściu"
|
||||
|
||||
#: pretix/base/models/checkin.py:95
|
||||
msgid "Allow multiple entries per ticket"
|
||||
msgstr ""
|
||||
msgstr "Pozwól na wielokrotne wejścia na ten sam bilet"
|
||||
|
||||
#: pretix/base/models/checkin.py:96
|
||||
msgid ""
|
||||
"Use this option to turn off warnings if a ticket is scanned a second time."
|
||||
msgstr ""
|
||||
"Użyj tej opcji by wyłączyć ostrzeżenie, że bilet jest skanowany ponownie."
|
||||
|
||||
#: pretix/base/models/checkin.py:100
|
||||
#, fuzzy
|
||||
#| msgid "Ticket checked in"
|
||||
msgid "Automatically check out everyone at"
|
||||
msgstr "Bilet zameldowany"
|
||||
msgstr "Automatycznie zamelduj wszystkich w"
|
||||
|
||||
#: pretix/base/models/checkin.py:106
|
||||
msgid "Sales channels to automatically check in"
|
||||
msgstr ""
|
||||
msgstr "Kanały sprzedaży do automatycznego sprawdzania biletów"
|
||||
|
||||
#: pretix/base/models/checkin.py:107
|
||||
msgid ""
|
||||
@@ -3450,18 +3423,16 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/checkin.py:340
|
||||
#, fuzzy
|
||||
#| msgid "Country"
|
||||
msgid "Entry"
|
||||
msgstr "Kraj"
|
||||
msgstr "Wejście"
|
||||
|
||||
#: pretix/base/models/checkin.py:341
|
||||
msgid "Exit"
|
||||
msgstr ""
|
||||
msgstr "Wyjście"
|
||||
|
||||
#: pretix/base/models/checkin.py:358
|
||||
msgid "Unknown ticket"
|
||||
msgstr ""
|
||||
msgstr "Bilet nieznany"
|
||||
|
||||
#: pretix/base/models/checkin.py:359
|
||||
msgid "Ticket not paid"
|
||||
@@ -3469,7 +3440,7 @@ msgstr "Bilet nie został opłacony"
|
||||
|
||||
#: pretix/base/models/checkin.py:360
|
||||
msgid "Forbidden by custom rule"
|
||||
msgstr ""
|
||||
msgstr "Zabronione przez niestandardową regułę"
|
||||
|
||||
#: pretix/base/models/checkin.py:361
|
||||
#, fuzzy
|
||||
@@ -3497,7 +3468,7 @@ msgstr "Przedsprzedaż nierozpoczęta"
|
||||
|
||||
#: pretix/base/models/checkin.py:365
|
||||
msgid "Ticket code is ambiguous on list"
|
||||
msgstr ""
|
||||
msgstr "Kod biletu jest niejednoznaczny na liście"
|
||||
|
||||
#: pretix/base/models/checkin.py:366
|
||||
#, fuzzy
|
||||
@@ -3518,14 +3489,12 @@ msgid "Ticket not valid at this time"
|
||||
msgstr "Produkt nie będzie sprzedawany przed podaną datą."
|
||||
|
||||
#: pretix/base/models/customers.py:55
|
||||
#, fuzzy
|
||||
#| msgid "Attendee name"
|
||||
msgid "Provider name"
|
||||
msgstr "Imię uczstnika"
|
||||
msgstr "Imię dostarczyciela"
|
||||
|
||||
#: pretix/base/models/customers.py:60
|
||||
msgid "Login button label"
|
||||
msgstr ""
|
||||
msgstr "Etykieta przycisku logowania"
|
||||
|
||||
#: pretix/base/models/customers.py:64
|
||||
#, fuzzy
|
||||
@@ -3547,6 +3516,8 @@ msgid ""
|
||||
"The identifier may only contain letters, numbers, dots, dashes, and "
|
||||
"underscores. It must start and end with a letter or number."
|
||||
msgstr ""
|
||||
"Identyfikator może zawierać jedynie litery, cyfry, kropki, średniki i "
|
||||
"podkreślniki. Może zaczynać się i kończyć literą, lub cyfrą."
|
||||
|
||||
#: pretix/base/models/customers.py:299 pretix/base/models/orders.py:1410
|
||||
#: pretix/base/models/orders.py:2989 pretix/base/settings.py:1093
|
||||
@@ -3562,40 +3533,34 @@ msgstr "Proszę wybrać kraj"
|
||||
#: pretix/base/models/customers.py:370
|
||||
msgctxt "openidconnect"
|
||||
msgid "Confidential"
|
||||
msgstr ""
|
||||
msgstr "Poufne"
|
||||
|
||||
#: pretix/base/models/customers.py:371
|
||||
msgctxt "openidconnect"
|
||||
msgid "Public"
|
||||
msgstr ""
|
||||
msgstr "Publiczne"
|
||||
|
||||
#: pretix/base/models/customers.py:377
|
||||
#, fuzzy
|
||||
#| msgid "Cart positions"
|
||||
msgctxt "openidconnect"
|
||||
msgid "Authorization code"
|
||||
msgstr "Pozycje wózka"
|
||||
msgstr "Kod autoryzacyjny"
|
||||
|
||||
#: pretix/base/models/customers.py:378
|
||||
msgctxt "openidconnect"
|
||||
msgid "Implicit"
|
||||
msgstr ""
|
||||
msgstr "Domniemany"
|
||||
|
||||
#: pretix/base/models/customers.py:382
|
||||
msgid "OpenID Connect access (required)"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/customers.py:383
|
||||
#, fuzzy
|
||||
#| msgid "Creation date"
|
||||
msgid "Profile data (name, addresses)"
|
||||
msgstr "Data stworzenia"
|
||||
msgstr "Dane profilu (nazwa, adresy)"
|
||||
|
||||
#: pretix/base/models/customers.py:403
|
||||
#, fuzzy
|
||||
#| msgid "Payment fee"
|
||||
msgid "Client type"
|
||||
msgstr "Prowizja płatności"
|
||||
msgstr "Typ klienta"
|
||||
|
||||
#: pretix/base/models/customers.py:406
|
||||
#, fuzzy
|
||||
@@ -3605,11 +3570,11 @@ msgstr "Typ urządzenia"
|
||||
|
||||
#: pretix/base/models/customers.py:417
|
||||
msgid "Allowed access scopes"
|
||||
msgstr ""
|
||||
msgstr "Zakres dozwolonego dostępu"
|
||||
|
||||
#: pretix/base/models/customers.py:418
|
||||
msgid "Separate multiple values with spaces"
|
||||
msgstr ""
|
||||
msgstr "Rozdziel wiele wartości spacją"
|
||||
|
||||
#: pretix/base/models/devices.py:71 pretix/base/models/items.py:1478
|
||||
msgid "Internal identifier"
|
||||
@@ -3626,7 +3591,7 @@ msgstr "Identyfikator użyty przy innym pytaniu."
|
||||
#: pretix/control/templates/pretixcontrol/organizers/gates.html:16
|
||||
#: pretix/plugins/checkinlists/exporters.py:741
|
||||
msgid "Gate"
|
||||
msgstr ""
|
||||
msgstr "Bramka"
|
||||
|
||||
#: pretix/base/models/devices.py:132
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html:83
|
||||
@@ -3640,7 +3605,7 @@ msgstr "Data inicjalizacji"
|
||||
#: pretix/base/models/discount.py:45
|
||||
msgctxt "subevent"
|
||||
msgid "Dates can be mixed without limitation"
|
||||
msgstr ""
|
||||
msgstr "Daty mogą być mieszane bez ograniczeń"
|
||||
|
||||
#: pretix/base/models/discount.py:46
|
||||
#, fuzzy
|
||||
@@ -3652,7 +3617,7 @@ msgstr "Produkt nie będzie sprzedawany przed podaną datą."
|
||||
#: pretix/base/models/discount.py:47
|
||||
msgctxt "subevent"
|
||||
msgid "Each matching product must be for a different date"
|
||||
msgstr ""
|
||||
msgstr "Każdy pasujący produkt musi być na inną datę"
|
||||
|
||||
#: pretix/base/models/discount.py:65 pretix/base/models/items.py:1010
|
||||
#: pretix/base/models/items.py:1287 pretix/base/models/items.py:1511
|
||||
@@ -3673,7 +3638,7 @@ msgstr "Wszystkie produkty (łącznie z nowo stworzonymi)"
|
||||
|
||||
#: pretix/base/models/discount.py:97
|
||||
msgid "Apply to specific products"
|
||||
msgstr ""
|
||||
msgstr "Zastosuj do wybranych produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:102
|
||||
#, fuzzy
|
||||
@@ -3683,11 +3648,11 @@ msgstr "Ograniczenie do produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:103 pretix/base/models/discount.py:158
|
||||
msgid "Discounts never apply to bundled products"
|
||||
msgstr ""
|
||||
msgstr "Zniżki nigdy nie obowiązuja dla zgrupowanych produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:107 pretix/base/models/discount.py:162
|
||||
msgid "Ignore products discounted by a voucher"
|
||||
msgstr ""
|
||||
msgstr "Ignoruj produkty ze zniżką z kuponu"
|
||||
|
||||
#: pretix/base/models/discount.py:108
|
||||
msgid ""
|
||||
@@ -3696,14 +3661,18 @@ msgid ""
|
||||
"use a voucher only to e.g. unlock a hidden product or gain access to sold-"
|
||||
"out quota will still be considered."
|
||||
msgstr ""
|
||||
"Jeżeli ta opcja jest zaznaczona, produkty które już otrzymały zniżkę z "
|
||||
"vouchera nie będą kwalifikować się do tej zniżki. Podukty przy których użyto "
|
||||
"vouchera np po to by odblokować ukryty produkt, lub uzyskać dostęp do "
|
||||
"wyprzedanego produktu nadal będą kwalifikować się do zniżki."
|
||||
|
||||
#: pretix/base/models/discount.py:113
|
||||
msgid "Minimum number of matching products"
|
||||
msgstr ""
|
||||
msgstr "Minimalna ilość zgodnych produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:117
|
||||
msgid "Minimum gross value of matching products"
|
||||
msgstr ""
|
||||
msgstr "Minimalna wartość brutto zgodnych produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:125
|
||||
#, fuzzy
|
||||
@@ -3726,11 +3695,11 @@ msgstr "Ograniczenie do produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:137
|
||||
msgid "Percentual discount on matching products"
|
||||
msgstr ""
|
||||
msgstr "Procentowa zniżka na zgodnych produktach"
|
||||
|
||||
#: pretix/base/models/discount.py:144
|
||||
msgid "Apply discount only to this number of matching products"
|
||||
msgstr ""
|
||||
msgstr "Zastosuj zniżkę tylko dla tej ilości zgodnych produktów"
|
||||
|
||||
#: pretix/base/models/discount.py:146
|
||||
msgid ""
|
||||
@@ -4144,7 +4113,7 @@ msgstr "Opis kategorii"
|
||||
|
||||
#: pretix/base/models/items.py:107
|
||||
msgid "Products in this category are add-on products"
|
||||
msgstr "Produkty w tej kategorii są dodatkami."
|
||||
msgstr "Produkty w tej kategorii są dodatkami"
|
||||
|
||||
#: pretix/base/models/items.py:108
|
||||
msgid ""
|
||||
@@ -4261,7 +4230,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:443
|
||||
msgid "Whether or not buying this product allows a person to enter your event"
|
||||
msgstr "Jeśli wybrane, kupno produktu umożliwia wstęp na wydarzenie."
|
||||
msgstr "Jeśli wybrane, kupno produktu umożliwia wstęp na wydarzenie"
|
||||
|
||||
#: pretix/base/models/items.py:448
|
||||
#, fuzzy
|
||||
@@ -4375,7 +4344,7 @@ msgid ""
|
||||
"many times. If you keep the field empty or set it to 0, there is no special "
|
||||
"limit for this product."
|
||||
msgstr ""
|
||||
"Ten produkt może zostać zamówiony tylko jeśli wózek użytkownika zawiera go "
|
||||
"Ten produkt może zostać zamówiony tylko jeśli koszyk użytkownika zawiera go "
|
||||
"przynajmniej tyle razy. Pozostawienie pola pustego lub wprowadzenie 0 "
|
||||
"wyłącza ten limit."
|
||||
|
||||
@@ -5001,7 +4970,7 @@ msgstr "Calkowita objętość"
|
||||
|
||||
#: pretix/base/models/items.py:1846 pretix/control/forms/item.py:363
|
||||
msgid "Leave empty for an unlimited number of tickets."
|
||||
msgstr "Jeśli puste, ilość biletów będzie nielimitowana"
|
||||
msgstr "Jeśli puste, ilość biletów będzie nielimitowana."
|
||||
|
||||
#: pretix/base/models/items.py:1850 pretix/base/models/orders.py:1361
|
||||
#: pretix/base/models/orders.py:2738
|
||||
@@ -5104,7 +5073,7 @@ msgstr "Zamówienie {val}"
|
||||
#: pretix/base/models/log.py:167
|
||||
#, python-brace-format
|
||||
msgid "Voucher {val}…"
|
||||
msgstr "Voucher {val}"
|
||||
msgstr "Voucher {val}…"
|
||||
|
||||
#: pretix/base/models/log.py:177
|
||||
#, python-brace-format
|
||||
@@ -5553,13 +5522,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Osoby z tym ustawieniem mają dostęp do większości danych wydarzeń, np. "
|
||||
"poprzez raporty prywatności. Tylko zaufane osoby powinny posiadać to "
|
||||
"uprawnienie."
|
||||
"uprawnienie!"
|
||||
|
||||
#: pretix/base/models/organizer.py:283
|
||||
#, fuzzy
|
||||
#| msgid "Internal comment"
|
||||
msgid "Can manage customer accounts"
|
||||
msgstr "Komentarz wewnętrzny"
|
||||
msgstr "Może zarządzać kontami użytkownikó∑"
|
||||
|
||||
#: pretix/base/models/organizer.py:287
|
||||
#, fuzzy
|
||||
@@ -6528,7 +6495,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/payment.py:1180
|
||||
msgid "Payment process description during checkout"
|
||||
msgstr ""
|
||||
msgstr "Opis procesu płatności podczas podsumowania"
|
||||
|
||||
#: pretix/base/payment.py:1181
|
||||
msgid ""
|
||||
@@ -7045,10 +7012,8 @@ msgid "Seat: seat number"
|
||||
msgstr "Ulica i numer domu"
|
||||
|
||||
#: pretix/base/pdf.py:487
|
||||
#, fuzzy
|
||||
#| msgid "Date and time"
|
||||
msgid "Date and time of first scan"
|
||||
msgstr "Data i czas"
|
||||
msgstr "Data i czas pierwszego skanu"
|
||||
|
||||
#: pretix/base/pdf.py:493
|
||||
#, fuzzy
|
||||
@@ -7178,7 +7143,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/services/cart.py:104
|
||||
msgid "Unknown cart position."
|
||||
msgstr ""
|
||||
msgstr "Nieznana pozycja koszyka."
|
||||
|
||||
#: pretix/base/services/cart.py:105
|
||||
msgctxt "subevent"
|
||||
@@ -7238,8 +7203,14 @@ msgid_plural ""
|
||||
"We removed %(product)s from your cart as you can not buy less than %(min)s "
|
||||
"items of it."
|
||||
msgstr[0] ""
|
||||
"Produkt %(product)s został usunięty z koszyka. Minimalna ilość do zakupu to "
|
||||
"%(min)s."
|
||||
msgstr[1] ""
|
||||
"Produkty %(product)s zostały usunięte z koszyka. Minimalna ilość do zakupu "
|
||||
"to %(min)s."
|
||||
msgstr[2] ""
|
||||
"Produkty %(product)s zostały usunięte z koszyka. Minimalna ilość do zakupu "
|
||||
"to %(min)s."
|
||||
|
||||
#: pretix/base/services/cart.py:134 pretix/base/services/orders.py:154
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:157
|
||||
@@ -7266,12 +7237,16 @@ msgid ""
|
||||
"The booking period for this event has not yet started. The affected "
|
||||
"positions have been removed from your cart."
|
||||
msgstr ""
|
||||
"Nie rozpoczęto jeszcze sprzedaży biletów na to wydarzenie. Bilety zostały "
|
||||
"usunięte z koszyka."
|
||||
|
||||
#: pretix/base/services/cart.py:141 pretix/base/services/orders.py:182
|
||||
msgid ""
|
||||
"The booking period for one of the events in your cart has ended. The "
|
||||
"affected positions have been removed from your cart."
|
||||
msgstr ""
|
||||
"Sprzedaż biletów na to wydarzenie została już zakończona. Bilety zostały "
|
||||
"usunięte z koszyka."
|
||||
|
||||
#: pretix/base/services/cart.py:143
|
||||
msgid "The entered price is not a number."
|
||||
@@ -7761,6 +7736,8 @@ msgid ""
|
||||
"You selected a membership for the product \"{product}\" which does not "
|
||||
"require a membership."
|
||||
msgstr ""
|
||||
"Wybrano członkowstwo dla produktu \"{product}\", któryh nie wymaga "
|
||||
"członkowstwa."
|
||||
|
||||
#: pretix/base/services/memberships.py:113
|
||||
#, python-brace-format
|
||||
@@ -7768,13 +7745,12 @@ msgid ""
|
||||
"You selected the product \"{product}\" which requires an active membership "
|
||||
"to be selected."
|
||||
msgstr ""
|
||||
"Wybrano produkt \"{product}\" który wymaga wybrania aktywnego członkowstwa."
|
||||
|
||||
#: pretix/base/services/memberships.py:142
|
||||
#, fuzzy
|
||||
#| msgid "You cannot select an item that belongs to a different event."
|
||||
msgid ""
|
||||
"You selected a membership that is connected to a different customer account."
|
||||
msgstr "Wybrano przedmiot należący do innego wydarzenia."
|
||||
msgstr "Wybrano członkowstwo, które jest połączone z innym kontem klienta."
|
||||
|
||||
#: pretix/base/services/memberships.py:147
|
||||
#, fuzzy
|
||||
@@ -7792,6 +7768,8 @@ msgid ""
|
||||
"You selected a membership that is valid from {start} to {end}, but selected "
|
||||
"an event taking place at {date}."
|
||||
msgstr ""
|
||||
"Wybrano członkowstwo które jest ważne od {start} do {end}, ale wybrane "
|
||||
"wydarzenie ma miejsce {date}."
|
||||
|
||||
#: pretix/base/services/memberships.py:174
|
||||
#, python-brace-format
|
||||
@@ -7799,6 +7777,8 @@ msgid ""
|
||||
"You selected a membership of type \"{type}\", which is not allowed for the "
|
||||
"product \"{product}\"."
|
||||
msgstr ""
|
||||
"Wybrano członkowstwo typu \"{type}\", które nie jest dozwolone dla produktu "
|
||||
"\"{product}\"."
|
||||
|
||||
#: pretix/base/services/memberships.py:183
|
||||
#, python-brace-format
|
||||
@@ -7845,6 +7825,8 @@ msgid ""
|
||||
"The price of some of the items in your cart has changed in the meantime. "
|
||||
"Please see below for details."
|
||||
msgstr ""
|
||||
"Cena części produktów z koszyka zmieniła się w międzyczasie. Szczegóły "
|
||||
"poniżej."
|
||||
|
||||
#: pretix/base/services/orders.py:141
|
||||
msgid "An internal error occurred, please try again."
|
||||
@@ -7869,8 +7851,14 @@ msgid_plural ""
|
||||
"You cannot select more than %(max)s items of the product %(product)s. We "
|
||||
"removed the surplus items from your cart."
|
||||
msgstr[0] ""
|
||||
"Nie można wybrać więcej niż %(max)s szt produktu %(product)s. Nadmiar został "
|
||||
"usunięty z koszyka."
|
||||
msgstr[1] ""
|
||||
"Nie można wybrać więcej niż %(max)s szt produktu %(product)s. Nadmiar został "
|
||||
"usunięty z koszyka."
|
||||
msgstr[2] ""
|
||||
"Nie można wybrać więcej niż %(max)s szt produktu %(product)s. Nadmiar został "
|
||||
"usunięty z koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:155
|
||||
#, fuzzy
|
||||
@@ -7882,7 +7870,7 @@ msgstr "Produkt może być kupiony tylko przy użyciu vouchera."
|
||||
msgid ""
|
||||
"The voucher code used for one of the items in your cart is not known in our "
|
||||
"database."
|
||||
msgstr ""
|
||||
msgstr "Nieznany kod vouchera."
|
||||
|
||||
#: pretix/base/services/orders.py:163
|
||||
msgid ""
|
||||
@@ -7890,24 +7878,32 @@ msgid ""
|
||||
"used the maximum number of times allowed. We removed this item from your "
|
||||
"cart."
|
||||
msgstr ""
|
||||
"Voucher na jeden z produktów w koszyku został już wykorzystany maksymalną "
|
||||
"ilość razy. Produkt usunięty z koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:167
|
||||
msgid ""
|
||||
"The voucher code used for one of the items in your cart has already been too "
|
||||
"often. We adjusted the price of the item in your cart."
|
||||
msgstr ""
|
||||
"Voucher użyty dla jednego z produktów w koszyku został użyty zbyt wiele "
|
||||
"razy. Cena produktu została zaktualizowana."
|
||||
|
||||
#: pretix/base/services/orders.py:171
|
||||
msgid ""
|
||||
"The voucher code used for one of the items in your cart is expired. We "
|
||||
"removed this item from your cart."
|
||||
msgstr ""
|
||||
"Voucher na jeden z produktów z koszyka jest już nie ważny. Produkt usunięto "
|
||||
"z koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:174
|
||||
msgid ""
|
||||
"The voucher code used for one of the items in your cart is not valid for "
|
||||
"this item. We removed this item from your cart."
|
||||
msgstr ""
|
||||
"Voucher użyty do jednego z produktów z koszyka nie jest ważny z tym "
|
||||
"produktem. Produkt został usunięty z koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:176
|
||||
msgid "You need a valid voucher code to order one of the products."
|
||||
@@ -7918,18 +7914,24 @@ msgid ""
|
||||
"The booking period for one of the events in your cart has not yet started. "
|
||||
"The affected positions have been removed from your cart."
|
||||
msgstr ""
|
||||
"Nie rozpoczęto jeszcze sprzedaży biletów na wydarzenie. Prodykty usunięto z "
|
||||
"koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:185
|
||||
msgid ""
|
||||
"One of the seats in your order was invalid, we removed the position from "
|
||||
"your cart."
|
||||
msgstr ""
|
||||
"Jedno z miejsc wybranych w zamówieniu było nieprawidłowe i zostało usunięte "
|
||||
"z koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:186
|
||||
msgid ""
|
||||
"One of the seats in your order has been taken in the meantime, we removed "
|
||||
"the position from your cart."
|
||||
msgstr ""
|
||||
"Jedno z miejsc z zamówienia zostało zajęte w miedzyczasie i zostało usunięte "
|
||||
"z koszyka."
|
||||
|
||||
#: pretix/base/services/orders.py:202
|
||||
#, python-format
|
||||
@@ -8276,6 +8278,8 @@ msgid ""
|
||||
"Independent of your choice, the cart will show gross prices as this is the "
|
||||
"price that needs to be paid."
|
||||
msgstr ""
|
||||
"Niezależnie od wyboru koszyk będzie pokazywać kwotę brutto, która musi być "
|
||||
"zapłacona."
|
||||
|
||||
#: pretix/base/settings.py:335
|
||||
msgid "Hide prices on attendee ticket page"
|
||||
@@ -8578,12 +8582,12 @@ msgstr ""
|
||||
#: pretix/base/settings.py:783
|
||||
msgid ""
|
||||
"The number of minutes the items in a user's cart are reserved for this user."
|
||||
msgstr ""
|
||||
msgstr "Ilość minut którą produkty są zarezerwowane w koszyku tego użytkownika."
|
||||
|
||||
#: pretix/base/settings.py:792
|
||||
msgid ""
|
||||
"Directly redirect to check-out after a product has been added to the cart."
|
||||
msgstr ""
|
||||
msgstr "Przekieruj do podsumowania zaraz po dodaniu produktu do koszyka."
|
||||
|
||||
#: pretix/base/settings.py:801
|
||||
#, fuzzy
|
||||
@@ -17603,7 +17607,7 @@ msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/settings.html:330
|
||||
msgid "Cart"
|
||||
msgstr ""
|
||||
msgstr "Koszyk"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/settings.html:338
|
||||
msgid ""
|
||||
@@ -18636,6 +18640,9 @@ msgid ""
|
||||
"overlapping discounts, the first one in the order of the list below will "
|
||||
"apply."
|
||||
msgstr ""
|
||||
"Produkty w koszyku mogą być pod wpływem tylko przez jednej zniżki. Jeżeli "
|
||||
"zastosowano wiele zniżek działać będzie tylko pierwsza, którą dodano do "
|
||||
"zamówienia."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/items/discounts.html:36
|
||||
msgid "You haven't created any discounts yet."
|
||||
@@ -22783,7 +22790,7 @@ msgstr "Data w serii wydarzeń"
|
||||
msgid ""
|
||||
"Are you sure you want to delete any cart positions with voucher "
|
||||
"<strong>%(voucher)s</strong>?"
|
||||
msgstr ""
|
||||
msgstr "Czy na pewno usunąć produkty z voucherem <strong>%(voucher)s</strong>?"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete_carts.html:10
|
||||
msgid ""
|
||||
@@ -22807,6 +22814,8 @@ msgid ""
|
||||
"This voucher is currently used in %(number)s cart sessions and might not be "
|
||||
"free to use until the cart sessions expire."
|
||||
msgstr ""
|
||||
"Ten voucher jest obecnie używany w %(number)s aktywnych koszyków i może nie "
|
||||
"być dostępny przez jakiś czas, aż do końca sesji tych koszyków."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html:28
|
||||
#, fuzzy
|
||||
@@ -28550,6 +28559,8 @@ msgid ""
|
||||
"For some of the products in your cart, you can choose additional options "
|
||||
"before you continue."
|
||||
msgstr ""
|
||||
"Dla niektórych produktów w koszyku można wybrać dodatkowe opcje przed "
|
||||
"kontynuowaniem."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/checkout_addons.html:13
|
||||
msgid "We're now trying to book these add-ons for you!"
|
||||
@@ -28864,6 +28875,8 @@ msgid ""
|
||||
"cookie to remember who you are and what is in your cart. Please change your "
|
||||
"browser settings accordingly."
|
||||
msgstr ""
|
||||
"Przeglądarka nie obsługuje cookies. Cookies są wymagane dla działania "
|
||||
"sklepu. Proszę zmienić przeglądarkę, lub jej ustawienia."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:16
|
||||
#, python-format
|
||||
@@ -29015,7 +29028,7 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/voucher.html:240
|
||||
#, python-format
|
||||
msgid "Add %(item)s, %(var)s to cart"
|
||||
msgstr ""
|
||||
msgstr "Dodaj %(item)s, %(var)s do koszyka"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:191
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:325
|
||||
@@ -29060,7 +29073,7 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/voucher.html:385
|
||||
#, python-format
|
||||
msgid "Add %(item)s to cart"
|
||||
msgstr ""
|
||||
msgstr "Dodaj %(item)s do koszyka"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:338
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_product_list.html:357
|
||||
@@ -29186,12 +29199,12 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:288
|
||||
#, python-format
|
||||
msgid "Remove %(item)s from your cart"
|
||||
msgstr ""
|
||||
msgstr "Usuń %(item)s z koszyka"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:291
|
||||
#, python-format
|
||||
msgid "Remove one %(item)s from your cart"
|
||||
msgstr ""
|
||||
msgstr "Usuń 1 sztukę %(item)s z koszyka"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:293
|
||||
#, python-format
|
||||
@@ -29199,6 +29212,7 @@ msgid ""
|
||||
"Remove one %(item)s from your cart. You currently have %(count)s in your "
|
||||
"cart."
|
||||
msgstr ""
|
||||
"Usuń jedną sztukę %(item)s z koszyka. Obecnie w koszyku jest %(count)s sztuk."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:301
|
||||
msgid "We're trying to reserve another one for you!"
|
||||
@@ -29212,12 +29226,12 @@ msgstr ""
|
||||
msgid ""
|
||||
"Once the items are in your cart, you will have %(time)s minutes to complete "
|
||||
"your purchase."
|
||||
msgstr ""
|
||||
msgstr "Produkty dodane do koszyka są rezerwowane na %(time)s minut."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:321
|
||||
#, python-format
|
||||
msgid "Add one more %(item)s to your cart"
|
||||
msgstr ""
|
||||
msgstr "Dodaj jeszcze jedną sztukę %(item)s do koszyka"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:323
|
||||
#, python-format
|
||||
@@ -29225,6 +29239,8 @@ msgid ""
|
||||
"Add one more %(item)s to your cart. You currently have %(count)s in your "
|
||||
"cart."
|
||||
msgstr ""
|
||||
"Dodaj jeszcze jedną sztukę %(item)s do koszyka. W koszyku obecnie znajduje "
|
||||
"się %(count)s sztuk."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:377
|
||||
#: pretix/presale/templates/pretixpresale/event/order_giftcard.html:20
|
||||
@@ -29280,7 +29296,7 @@ msgstr "Przejdź do podsumowania"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart_box.html:43
|
||||
msgid "Empty cart"
|
||||
msgstr ""
|
||||
msgstr "Opróżnij koszyk"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart_box.html:48
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:236
|
||||
@@ -29774,7 +29790,7 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:243
|
||||
msgid "If you already ordered a ticket"
|
||||
msgstr ""
|
||||
msgstr "Jeżeli bilet jest już zamówiony"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:247
|
||||
msgid ""
|
||||
@@ -29786,7 +29802,7 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:256
|
||||
msgid "Resend order link"
|
||||
msgstr ""
|
||||
msgstr "Wyślij ponownie link do zamówienia"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:12
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:29
|
||||
@@ -30228,10 +30244,8 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/resend_link.html:4
|
||||
#: pretix/presale/templates/pretixpresale/event/resend_link.html:11
|
||||
#, fuzzy
|
||||
#| msgid "Pending orders"
|
||||
msgid "Resend order links"
|
||||
msgstr "Zamówienia w toku"
|
||||
msgstr "Wyślij ponownie linki do zamówienia"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/resend_link.html:15
|
||||
msgid ""
|
||||
@@ -30964,6 +30978,8 @@ msgid ""
|
||||
"We've added you to the waiting list. We will send an email to {email} as "
|
||||
"soon as this product gets available again."
|
||||
msgstr ""
|
||||
"Dodaliśmy Cię do listy oczekujących. Wyślemi Ci mail na {email} kiedy "
|
||||
"produkt będzie znów dostępny."
|
||||
|
||||
#: pretix/presale/views/waiting.py:160
|
||||
#, fuzzy
|
||||
|
||||
@@ -25,9 +25,18 @@ from django.forms.models import ModelChoiceIterator
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.plugins.badges.models import BadgeItem, BadgeLayout
|
||||
from pretix.plugins.badges.templates import TEMPLATES
|
||||
|
||||
|
||||
class BadgeLayoutForm(forms.ModelForm):
|
||||
template = forms.ChoiceField(
|
||||
label=_('Template'),
|
||||
help_text=_('You can modify the layout or change to a different page size in the next step.'),
|
||||
choices=((k, v['label']) for k, v in TEMPLATES.items()),
|
||||
widget=forms.RadioSelect,
|
||||
initial='a6l',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = BadgeLayout
|
||||
fields = ('name',)
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django.utils.text import format_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from reportlab.lib import pagesizes
|
||||
from reportlab.lib.units import mm
|
||||
|
||||
|
||||
def _simple_template(w, h):
|
||||
name_size = max(min(20, w / 20), 12) # Heuristic for font size
|
||||
company_size = name_size - 2
|
||||
return [
|
||||
{
|
||||
"type": "textarea",
|
||||
"page": 1,
|
||||
"locale": "",
|
||||
"left": "5.00",
|
||||
"bottom": "%.2f" % (((h - company_size * 1.5 - name_size) / 2 + company_size * 1.5) / mm),
|
||||
"fontsize": name_size,
|
||||
"lineheight": "1",
|
||||
"color": [0, 0, 0, 1],
|
||||
"fontfamily": "Open Sans",
|
||||
"bold": True,
|
||||
"italic": False,
|
||||
"width": "%.2f" % (w / mm - 10),
|
||||
"downward": False,
|
||||
"content": "attendee_name",
|
||||
"text": "John Doe",
|
||||
"text_i18n": {},
|
||||
"rotation": 0,
|
||||
"align": "center",
|
||||
},
|
||||
{
|
||||
"type": "textarea",
|
||||
"page": 1,
|
||||
"locale": "",
|
||||
"left": "5.00",
|
||||
"bottom": "%.2f" % ((((h - company_size * 1.5 - name_size) / 2) + company_size) / mm),
|
||||
"fontsize": company_size,
|
||||
"lineheight": "1",
|
||||
"color": [0, 0, 0, 1],
|
||||
"fontfamily": "Open Sans",
|
||||
"bold": False,
|
||||
"italic": False,
|
||||
"width": "%.2f" % (w / mm - 10),
|
||||
"downward": True,
|
||||
"content": "attendee_company",
|
||||
"text": "Sample company",
|
||||
"text_i18n": {},
|
||||
"rotation": 0,
|
||||
"align": "center",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
TEMPLATES = {
|
||||
"a6l": {
|
||||
"label": _("A6 landscape"),
|
||||
"pagesize": pagesizes.landscape(pagesizes.A6),
|
||||
"layout": _simple_template(*pagesizes.landscape(pagesizes.A6)),
|
||||
},
|
||||
"a6p": {
|
||||
"label": _("A6 portrait"),
|
||||
"pagesize": pagesizes.portrait(pagesizes.A6),
|
||||
"layout": _simple_template(*pagesizes.portrait(pagesizes.A6)),
|
||||
},
|
||||
"a7l": {
|
||||
"label": _("A7 landscape"),
|
||||
"pagesize": pagesizes.landscape(pagesizes.A7),
|
||||
"layout": _simple_template(*pagesizes.landscape(pagesizes.A7)),
|
||||
},
|
||||
"a7p": {
|
||||
"label": _("A7 portrait"),
|
||||
"pagesize": pagesizes.portrait(pagesizes.A7),
|
||||
"layout": _simple_template(*pagesizes.portrait(pagesizes.A7)),
|
||||
},
|
||||
"82x203butterfly": {
|
||||
"label": format_lazy(_("{width} x {height} mm butterfly badge"), width=82, height=203),
|
||||
"pagesize": (82 * mm, 203 * mm),
|
||||
"layout": [
|
||||
{
|
||||
"type": "textarea",
|
||||
"page": 1,
|
||||
"locale": "",
|
||||
"left": "5.00",
|
||||
"bottom": "152.55",
|
||||
"fontsize": "20.0",
|
||||
"lineheight": "1",
|
||||
"color": [0, 0, 0, 1],
|
||||
"fontfamily": "Open Sans",
|
||||
"bold": True,
|
||||
"italic": False,
|
||||
"width": "72.00",
|
||||
"downward": False,
|
||||
"content": "attendee_name",
|
||||
"text": "John Doe",
|
||||
"text_i18n": {},
|
||||
"rotation": 0,
|
||||
"align": "center",
|
||||
},
|
||||
{
|
||||
"type": "textarea",
|
||||
"page": 1,
|
||||
"locale": "",
|
||||
"left": "5.00",
|
||||
"bottom": "144.55",
|
||||
"fontsize": "18.0",
|
||||
"lineheight": "1",
|
||||
"color": [0, 0, 0, 1],
|
||||
"fontfamily": "Open Sans",
|
||||
"bold": False,
|
||||
"italic": False,
|
||||
"width": "72.00",
|
||||
"downward": False,
|
||||
"content": "attendee_company",
|
||||
"text": "Sample company",
|
||||
"text_i18n": {},
|
||||
"rotation": 0,
|
||||
"align": "center",
|
||||
},
|
||||
{
|
||||
"type": "textarea",
|
||||
"page": 1,
|
||||
"locale": "",
|
||||
"left": "77.10",
|
||||
"bottom": "34.68",
|
||||
"fontsize": "20.0",
|
||||
"lineheight": "1",
|
||||
"color": [0, 0, 0, 1],
|
||||
"fontfamily": "Open Sans",
|
||||
"bold": True,
|
||||
"italic": False,
|
||||
"width": "72.00",
|
||||
"downward": False,
|
||||
"content": "attendee_name",
|
||||
"text": "John Doe",
|
||||
"text_i18n": {},
|
||||
"rotation": 180,
|
||||
"align": "center",
|
||||
},
|
||||
{
|
||||
"type": "textarea",
|
||||
"page": 1,
|
||||
"locale": "",
|
||||
"left": "77.06",
|
||||
"bottom": "44.28",
|
||||
"fontsize": "18.0",
|
||||
"lineheight": "1",
|
||||
"color": [0, 0, 0, 1],
|
||||
"fontfamily": "Open Sans",
|
||||
"bold": False,
|
||||
"italic": False,
|
||||
"width": "72.00",
|
||||
"downward": False,
|
||||
"content": "attendee_company",
|
||||
"text": "Sample company",
|
||||
"text_i18n": {},
|
||||
"rotation": 180,
|
||||
"align": "center",
|
||||
},
|
||||
],
|
||||
},
|
||||
"100x50": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=100, height=50),
|
||||
"pagesize": (100 * mm, 50 * mm),
|
||||
"layout": _simple_template(100 * mm, 50 * mm),
|
||||
},
|
||||
"83x50": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=83, height=50),
|
||||
"pagesize": (83 * mm, 50 * mm),
|
||||
"layout": _simple_template(83 * mm, 50 * mm),
|
||||
},
|
||||
"80x50": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=80, height=50),
|
||||
"pagesize": (80 * mm, 50 * mm),
|
||||
"layout": _simple_template(80 * mm, 50 * mm),
|
||||
},
|
||||
"75x52": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=75, height=52),
|
||||
"pagesize": (75 * mm, 52 * mm),
|
||||
"layout": _simple_template(75 * mm, 52 * mm),
|
||||
},
|
||||
"70x36": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=70, height=36),
|
||||
"pagesize": (70 * mm, 36 * mm),
|
||||
"layout": _simple_template(70 * mm, 36 * mm),
|
||||
},
|
||||
"63x29": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=63, height=29),
|
||||
"pagesize": (63.5 * mm, 29.6 * mm),
|
||||
"layout": _simple_template(63.5 * mm, 29.6 * mm),
|
||||
},
|
||||
"60x90": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=60, height=90),
|
||||
"pagesize": (60 * mm, 90 * mm),
|
||||
"layout": _simple_template(60 * mm, 90 * mm),
|
||||
},
|
||||
"54x90": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=54, height=90),
|
||||
"pagesize": (54 * mm, 90 * mm),
|
||||
"layout": _simple_template(54 * mm, 90 * mm),
|
||||
},
|
||||
"50x80": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=50, height=80),
|
||||
"pagesize": (50 * mm, 80 * mm),
|
||||
"layout": _simple_template(50 * mm, 80 * mm),
|
||||
},
|
||||
"40x75": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=40, height=75),
|
||||
"pagesize": (40 * mm, 75 * mm),
|
||||
"layout": _simple_template(40 * mm, 75 * mm),
|
||||
},
|
||||
"40x40": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=40, height=40),
|
||||
"pagesize": (40 * mm, 40 * mm),
|
||||
"layout": _simple_template(40 * mm, 40 * mm),
|
||||
},
|
||||
}
|
||||
@@ -18,21 +18,12 @@
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form_errors form %}
|
||||
{% bootstrap_field form.name layout="control" %}
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">
|
||||
{% trans "Badge design" %}
|
||||
</label>
|
||||
<div class="col-md-9">
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
You can modify the design after you saved this page.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% if form.template %}
|
||||
{% bootstrap_field form.template layout="control" %}
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
{% trans "Save & continue" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
#
|
||||
import json
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.staticfiles import finders
|
||||
from django.core.files import File
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.files.storage import default_storage
|
||||
from django.db import transaction
|
||||
from django.http import Http404
|
||||
@@ -37,6 +39,7 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from django.views.generic import CreateView, DetailView, ListView
|
||||
from pypdf import PdfWriter
|
||||
from reportlab.lib import pagesizes
|
||||
from reportlab.pdfgen import canvas
|
||||
|
||||
@@ -51,6 +54,7 @@ from pretix.plugins.badges.tasks import badges_create_pdf
|
||||
|
||||
from ...helpers.compat import CompatDeleteView
|
||||
from .models import BadgeLayout
|
||||
from .templates import TEMPLATES
|
||||
|
||||
|
||||
class LayoutListView(EventPermissionRequiredMixin, ListView):
|
||||
@@ -71,14 +75,32 @@ class LayoutCreate(EventPermissionRequiredMixin, CreateView):
|
||||
context_object_name = 'layout'
|
||||
success_url = '/ignored'
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
if self.copy_from:
|
||||
del form.fields['template']
|
||||
return form
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
form.instance.event = self.request.event
|
||||
if not self.request.event.badge_layouts.filter(default=True).exists():
|
||||
form.instance.default = True
|
||||
messages.success(self.request, _('The new badge layout has been created.'))
|
||||
if not self.copy_from:
|
||||
form.instance.layout = json.dumps(TEMPLATES[form.cleaned_data["template"]]["layout"])
|
||||
super().form_valid(form)
|
||||
if form.instance.background and form.instance.background.name:
|
||||
if not self.copy_from:
|
||||
p = PdfWriter()
|
||||
p.add_blank_page(
|
||||
width=Decimal('%.5f' % TEMPLATES[form.cleaned_data["template"]]["pagesize"][0]),
|
||||
height=Decimal('%.5f' % TEMPLATES[form.cleaned_data["template"]]["pagesize"][1]),
|
||||
)
|
||||
buffer = BytesIO()
|
||||
p.write(buffer)
|
||||
buffer.seek(0)
|
||||
form.instance.background.save('background.pdf', ContentFile(buffer.read()))
|
||||
elif form.instance.background and form.instance.background.name:
|
||||
form.instance.background.save('background.pdf', form.instance.background)
|
||||
form.instance.log_action('pretix.plugins.badges.layout.added', user=self.request.user,
|
||||
data=dict(form.cleaned_data))
|
||||
|
||||
+31
-23
@@ -2,33 +2,41 @@
|
||||
{% load ibanformat %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
<p>{% blocktrans trimmed %}
|
||||
After completing your purchase, we will ask you to transfer the money to the following
|
||||
bank account, using a personal reference code:
|
||||
{% endblocktrans %}</p>
|
||||
{% if details or code %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
After completing your purchase, we will ask you to transfer the money to the following
|
||||
bank account, using a personal reference code:
|
||||
{% endblocktrans %}</p>
|
||||
|
||||
{% if settings.bank_details_type == "sepa" %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Account holder" %}: </dt><dd>{{ settings.bank_details_sepa_name }}</dd>
|
||||
<dt>{% trans "IBAN" %}: </dt><dd>{{ settings.bank_details_sepa_iban|ibanformat }}</dd>
|
||||
<dt>{% trans "BIC" %}: </dt><dd>{{ settings.bank_details_sepa_bic }}</dd>
|
||||
<dt>{% trans "Bank" %}: </dt><dd>{{ settings.bank_details_sepa_bank }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
{% if not code %}<div class="user-select-none" data-toggle="tooltip" title="{% trans "Please do not yet start a payment. We'll assign you a personal reference code after you completed the order." %}">{% endif %}
|
||||
{% if settings.bank_details_type == "sepa" %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Account holder" %}: </dt><dd>{{ settings.bank_details_sepa_name }}</dd>
|
||||
<dt>{% trans "IBAN" %}: </dt><dd>{{ settings.bank_details_sepa_iban|ibanformat }}</dd>
|
||||
<dt>{% trans "BIC" %}: </dt><dd>{{ settings.bank_details_sepa_bic }}</dd>
|
||||
<dt>{% trans "Bank" %}: </dt><dd>{{ settings.bank_details_sepa_bank }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
|
||||
{% if details %}
|
||||
{{ details|linebreaks }}
|
||||
{% endif %}
|
||||
{% if code %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Reference code (important):" %} </dt><dd><strong>{{ code }}</strong></dd>
|
||||
</dl>
|
||||
{% if not code %}</div>{% endif %}
|
||||
|
||||
{% if code %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Reference code (important):" %} </dt><dd><strong>{{ code }}</strong></dd>
|
||||
</dl>
|
||||
{% else %}
|
||||
<p>
|
||||
<strong>
|
||||
{% trans "We will assign you a personal reference code to use after you completed the order." %}
|
||||
</strong>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>
|
||||
<strong>
|
||||
{% trans "We will assign you a personal reference code to use after you completed the order." %}
|
||||
</strong>
|
||||
</p>
|
||||
<p>{% blocktrans trimmed %}
|
||||
After completing your purchase, we will ask you to transfer the money to our bank account, using a personal
|
||||
reference code.
|
||||
{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
{% if request.session.payment_banktransfer_send_invoice and request.session.payment_banktransfer_send_invoice_to %}
|
||||
<p>
|
||||
|
||||
+31
-23
@@ -2,33 +2,41 @@
|
||||
{% load ibanformat %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
<p>{% blocktrans trimmed %}
|
||||
After completing your purchase, we will ask you to transfer the money to the following
|
||||
bank account, using a personal reference code:
|
||||
{% endblocktrans %}</p>
|
||||
{% if details or code %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
After completing your purchase, we will ask you to transfer the money to the following
|
||||
bank account, using a personal reference code:
|
||||
{% endblocktrans %}</p>
|
||||
|
||||
{% if settings.bank_details_type == "sepa" %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Account holder" %}: </dt><dd>{{ settings.bank_details_sepa_name }}</dd>
|
||||
<dt>{% trans "IBAN" %}: </dt><dd>{{ settings.bank_details_sepa_iban|ibanformat }}</dd>
|
||||
<dt>{% trans "BIC" %}: </dt><dd>{{ settings.bank_details_sepa_bic }}</dd>
|
||||
<dt>{% trans "Bank" %}: </dt><dd>{{ settings.bank_details_sepa_bank }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
{% if not code %}<div class="user-select-none" data-toggle="tooltip" title="{% trans "Please do not yet start a payment. We'll assign you a personal reference code after you completed the order." %}">{% endif %}
|
||||
{% if settings.bank_details_type == "sepa" %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Account holder" %}: </dt><dd>{{ settings.bank_details_sepa_name }}</dd>
|
||||
<dt>{% trans "IBAN" %}: </dt><dd>{{ settings.bank_details_sepa_iban|ibanformat }}</dd>
|
||||
<dt>{% trans "BIC" %}: </dt><dd>{{ settings.bank_details_sepa_bic }}</dd>
|
||||
<dt>{% trans "Bank" %}: </dt><dd>{{ settings.bank_details_sepa_bank }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
|
||||
{% if details %}
|
||||
{{ details|linebreaks }}
|
||||
{% endif %}
|
||||
{% if code %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Reference code (important):" %} </dt><dd><strong>{{ code }}</strong></dd>
|
||||
</dl>
|
||||
{% if not code %}</div>{% endif %}
|
||||
|
||||
{% if code %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Reference code (important):" %} </dt><dd><strong>{{ code }}</strong></dd>
|
||||
</dl>
|
||||
{% else %}
|
||||
<p>
|
||||
<strong>
|
||||
{% trans "We will assign you a personal reference code to use after you completed the order." %}
|
||||
</strong>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>
|
||||
<strong>
|
||||
{% trans "We will assign you a personal reference code to use after you completed the order." %}
|
||||
</strong>
|
||||
</p>
|
||||
<p>{% blocktrans trimmed %}
|
||||
After completing your purchase, we will ask you to transfer the money to our bank account, using a personal
|
||||
reference code.
|
||||
{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
{% if form.fields %}
|
||||
<div class="col-md-12">
|
||||
|
||||
@@ -57,6 +57,7 @@ var pretixpaypal = {
|
||||
wechatpay: gettext('WeChat Pay'),
|
||||
mercadopago: gettext('Mercado Pago')
|
||||
},
|
||||
readyToSubmitApproval: false,
|
||||
|
||||
load: function () {
|
||||
if (pretixpaypal.paypal === null) {
|
||||
@@ -141,6 +142,8 @@ var pretixpaypal = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("visibilitychange", this.onApproveSubmit);
|
||||
},
|
||||
|
||||
ready: function () {
|
||||
@@ -225,12 +228,16 @@ var pretixpaypal = {
|
||||
|
||||
let method = pretixpaypal.paypage ? "wallet" : pretixpaypal.method.method;
|
||||
let selectorstub = "#payment_paypal_" + method;
|
||||
var $form = $(selectorstub + "_oid").closest("form");
|
||||
// Insert the tokens into the form so it gets submitted to the server
|
||||
// Insert the tokens into the form, so it gets submitted to the server
|
||||
$(selectorstub + "_oid").val(pretixpaypal.order_id);
|
||||
$(selectorstub + "_payer").val(pretixpaypal.payer_id);
|
||||
// and submit
|
||||
$form.get(0).submit();
|
||||
|
||||
// We are moving the submission to a separate function, which is also an EventListener, since
|
||||
// SFSafariView refuses to submit a form that is not visible. Unfortunately, that is exactly the case
|
||||
// when the ticket shop is used on iOS within an SFSafariView and the PayPal payment popup has not
|
||||
// closed itself quickly enough.
|
||||
pretixpaypal.readyToSubmitApproval = true;
|
||||
pretixpaypal.onApproveSubmit();
|
||||
|
||||
// billingToken: null
|
||||
// facilitatorAccessToken: "A21AAL_fEu0gDD-sIXyOy65a6MjgSJJrhmxuPcxxUGnL5gW2DzTxiiAksfoC4x8hD-BjeY1LsFVKl7ceuO7UR1a9pQr8Q_AVw"
|
||||
@@ -249,6 +256,16 @@ var pretixpaypal = {
|
||||
}
|
||||
},
|
||||
|
||||
onApproveSubmit: function() {
|
||||
if (document.visibilityState === "visible" && pretixpaypal.readyToSubmitApproval === true) {
|
||||
let method = pretixpaypal.paypage ? "wallet" : pretixpaypal.method.method;
|
||||
let selectorstub = "#payment_paypal_" + method;
|
||||
var $form = $(selectorstub + "_oid").closest("form");
|
||||
|
||||
$form.get(0).submit();
|
||||
}
|
||||
},
|
||||
|
||||
renderAPMs: function () {
|
||||
pretixpaypal.restore();
|
||||
let inputselector = $("input[name=payment][value=paypal_apm]");
|
||||
|
||||
@@ -570,7 +570,7 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
rate=a.tax_rate,
|
||||
)
|
||||
else:
|
||||
v.initial_price = v.display_price
|
||||
v.initial_price = v.suggested_price
|
||||
i.expand = any(v.initial for v in i.available_variations)
|
||||
else:
|
||||
i.initial = len(current_addon_products[i.pk, None])
|
||||
@@ -584,7 +584,7 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
rate=a.tax_rate,
|
||||
)
|
||||
else:
|
||||
i.initial_price = i.display_price
|
||||
i.initial_price = i.suggested_price
|
||||
|
||||
if items:
|
||||
formsetentry['categories'].append({
|
||||
@@ -1515,6 +1515,9 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
str(m) for m in self.confirm_messages.values()
|
||||
]
|
||||
}
|
||||
unlock_hashes = request.session.get('pretix_unlock_hashes', [])
|
||||
if unlock_hashes:
|
||||
meta_info['unlock_hashes'] = unlock_hashes
|
||||
for receiver, response in order_meta_from_request.send(sender=request.event, request=request):
|
||||
meta_info.update(response)
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.models import EventMetaValue, SubEventMetaValue
|
||||
|
||||
|
||||
def meta_filtersets(organizer, event=None):
|
||||
fields = {}
|
||||
if not (event or organizer).settings.event_list_filters:
|
||||
return fields
|
||||
for prop in organizer.meta_properties.filter(filter_public=True):
|
||||
if prop.choices:
|
||||
choices = [(v["key"], str(LazyI18nString(v["label"])) or v["key"]) for v in prop.choices]
|
||||
elif event:
|
||||
existing_values = set()
|
||||
if event.meta_data.get(prop.name):
|
||||
existing_values.add(event.meta_data.get(prop.name))
|
||||
existing_values |= set(SubEventMetaValue.objects.using(settings.DATABASE_REPLICA).filter(
|
||||
property=prop,
|
||||
subevent__event=event,
|
||||
subevent__event__live=True,
|
||||
subevent__event__is_public=True,
|
||||
subevent__active=True,
|
||||
subevent__is_public=True,
|
||||
).values_list("value", flat=True).distinct())
|
||||
choices = [(k, k) for k in sorted(existing_values)]
|
||||
else:
|
||||
existing_values = set()
|
||||
if prop.default:
|
||||
existing_values.add(prop.default)
|
||||
existing_values |= set(EventMetaValue.objects.using(settings.DATABASE_REPLICA).filter(
|
||||
property=prop,
|
||||
event__organizer=organizer,
|
||||
event__live=True,
|
||||
event__is_public=True,
|
||||
).values_list("value", flat=True).distinct())
|
||||
existing_values |= set(SubEventMetaValue.objects.using(settings.DATABASE_REPLICA).filter(
|
||||
property=prop,
|
||||
subevent__event__organizer=organizer,
|
||||
subevent__event__live=True,
|
||||
subevent__event__is_public=True,
|
||||
subevent__active=True,
|
||||
subevent__is_public=True,
|
||||
).values_list("value", flat=True).distinct())
|
||||
choices = [(k, k) for k in sorted(existing_values)]
|
||||
|
||||
choices.insert(0, ("", ""))
|
||||
if len(choices) > 1:
|
||||
fields[f"attr[{prop.name}]"] = {
|
||||
"label": str(prop.public_label) or prop.name,
|
||||
"choices": choices
|
||||
}
|
||||
return fields
|
||||
|
||||
|
||||
class EventListFilterForm(forms.Form):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.organizer = kwargs.pop('organizer')
|
||||
self.event = kwargs.pop('event', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
for k, v in meta_filtersets(self.organizer, self.event).items():
|
||||
self.fields[k] = forms.ChoiceField(
|
||||
label=v["label"],
|
||||
choices=v["choices"],
|
||||
required=False,
|
||||
)
|
||||
@@ -21,7 +21,6 @@
|
||||
<strong>{{ form.item.name }}{% if form.variation %}
|
||||
– {{ form.variation }}
|
||||
{% endif %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</h3>
|
||||
</summary>
|
||||
<div id="cp{{ form.pos.pk }}">
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
{% trans "Cart expired" %}
|
||||
{% endif %}
|
||||
</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</span>
|
||||
</h2>
|
||||
</summary>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<strong>{{ form.position.item.name }}{% if form.position.variation %}
|
||||
– {{ form.position.variation }}
|
||||
{% endif %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</h4>
|
||||
</summary>
|
||||
<div>
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<summary class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<strong>{% trans "Contact information" %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</h3>
|
||||
</summary>
|
||||
<div id="contact">
|
||||
@@ -40,8 +39,6 @@
|
||||
<strong>{% trans "Invoice information" %}{% if not event.settings.invoice_address_required and not event.settings.invoice_name_required %}
|
||||
{% trans "(optional)" %}
|
||||
{% endif %}</strong>
|
||||
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</h3>
|
||||
</summary>
|
||||
{% if addresses_data %}
|
||||
@@ -88,10 +85,7 @@
|
||||
<button type="button" data-id="{{ forloop.counter0 }}" name="copy"
|
||||
class="js-copy-answers btn btn-default btn-xs">{% trans "Copy answers from above" %}</button>
|
||||
{% endif %}
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</span>
|
||||
{% else %}
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
{% endif %}
|
||||
</h3>
|
||||
</summary>
|
||||
|
||||
@@ -97,8 +97,8 @@
|
||||
data-label-alt="{% trans "Hide variants" %}"
|
||||
aria-expanded="false"
|
||||
aria-label="{% blocktrans trimmed with item=item.name count=item.available_variations|length %}Show {{count}} variants of {{item}}{% endblocktrans %}">
|
||||
<span>{% trans "Show variants" %}</span>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
<span>{% trans "Show variants" %}</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -139,7 +139,15 @@
|
||||
placeholder="0"
|
||||
min="{% if event.settings.display_net_prices %}{{ var.display_price.net|money_numberfield:event.currency }}{% else %}{{ var.display_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
name="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}_price"
|
||||
title="{% blocktrans trimmed with item=var.value %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% if var.initial_price.gross != var.display_price.gross %}
|
||||
{% if event.settings.display_net_prices %}
|
||||
title="{% blocktrans trimmed with item=var.value price=var.display_price.net|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=var.value price=var.display_price.gross|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=var.value %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
step="any"
|
||||
value="{% if event.settings.display_net_prices %}{{ var.initial_price.net|money_numberfield:event.currency }}{% else %}{{ var.initial_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
>
|
||||
@@ -268,7 +276,15 @@
|
||||
id="price-item-{{ form.pos.pk }}-{{ item.pk }}"
|
||||
min="{% if event.settings.display_net_prices %}{{ item.display_price.net|money_numberfield:event.currency }}{% else %}{{ item.display_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
name="cp_{{ form.pos.pk }}_item_{{ item.id }}_price"
|
||||
title="{% blocktrans trimmed with item=item.name %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% if item.initial_price.gross != item.display_price.gross %}
|
||||
{% if event.settings.display_net_prices %}
|
||||
title="{% blocktrans trimmed with item=item.name price=item.display_price.net|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=item.name price=item.display_price.gross|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=item.name %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
value="{% if event.settings.display_net_prices %}{{ item.initial_price.net|money_numberfield:event.currency }}{% else %}{{ item.initial_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
step="any">
|
||||
</div>
|
||||
|
||||
@@ -10,16 +10,13 @@
|
||||
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
||||
<strong>{% trans "Your cart" %}</strong>
|
||||
</span>
|
||||
<span aria-hidden="true">
|
||||
<strong id="cart-deadline-short" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}" aria-hidden="true">
|
||||
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
|
||||
{{ cart.minutes_left|stringformat:"02d" }}:{{ cart.seconds_left|stringformat:"02d" }}
|
||||
{% else %}
|
||||
{% trans "Cart expired" %}
|
||||
{% endif %}
|
||||
</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</span>
|
||||
<strong id="cart-deadline-short" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}" aria-hidden="true">
|
||||
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
|
||||
{{ cart.minutes_left|stringformat:"02d" }}:{{ cart.seconds_left|stringformat:"02d" }}
|
||||
{% else %}
|
||||
{% trans "Cart expired" %}
|
||||
{% endif %}
|
||||
</strong>
|
||||
</h2>
|
||||
</summary>
|
||||
<div>
|
||||
|
||||
@@ -142,10 +142,6 @@
|
||||
<td>
|
||||
{% if new_pending_sum > 0 %}
|
||||
<strong>{% trans "You will need to pay" %}</strong>
|
||||
<br>
|
||||
<span class="text-muted">
|
||||
{% trans "Your entire order will be considered unpaid until you paid this difference." %}
|
||||
</span>
|
||||
{% else %}
|
||||
<strong>{% trans "You will be refunded" %}</strong>
|
||||
<br>
|
||||
@@ -184,6 +180,12 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% if new_pending_sum > 0 and order.status == "p" %}
|
||||
<div class="alert alert-warning">
|
||||
<strong>{% trans "Your entire order will be considered unpaid until you paid this difference." %}</strong>
|
||||
{% trans "You might not be able to use any of the tickets in your order until this payment has been received." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for k, l in request.POST.lists %}
|
||||
{% for v in l %}
|
||||
<input type="hidden" name="{{ k }}" value="{{ v }}">
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
data-label-alt="{% trans "Hide variants" %}"
|
||||
aria-expanded="false"
|
||||
aria-label="{% blocktrans trimmed with item=item.name count=item.available_variations|length %}Show {{count}} variants of {{ item }}{% endblocktrans %}">
|
||||
<span>{% trans "Show variants" %}</span>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
<span>{% trans "Show variants" %}</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -138,9 +138,17 @@
|
||||
placeholder="0"
|
||||
min="{% if event.settings.display_net_prices %}{{ var.display_price.net|money_numberfield:event.currency }}{% else %}{{ var.display_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
name="price_{{ item.id }}_{{ var.id }}"
|
||||
title="{% blocktrans trimmed with item=var.value %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% if var.suggested_price.gross != var.display_price.gross %}
|
||||
{% if event.settings.display_net_prices %}
|
||||
title="{% blocktrans trimmed with item=var.value price=var.display_price.net|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=var.value price=var.display_price.gross|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=var.value %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
step="any"
|
||||
value="{% if event.settings.display_net_prices %}{{ var.display_price.net|money_numberfield:event.currency }}{% else %}{{ var.display_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
value="{% if event.settings.display_net_prices %}{{ var.suggested_price.net|money_numberfield:event.currency }}{% else %}{{ var.suggested_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
>
|
||||
</div>
|
||||
<p>
|
||||
@@ -284,8 +292,16 @@
|
||||
{% if not ev.presale_is_running %}disabled{% endif %}
|
||||
min="{% if event.settings.display_net_prices %}{{ item.display_price.net|money_numberfield:event.currency }}{% else %}{{ item.display_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
name="price_{{ item.id }}"
|
||||
title="{% blocktrans trimmed with item=item.name %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
value="{% if event.settings.display_net_prices %}{{ item.display_price.net|money_numberfield:event.currency }}{% else %}{{ item.display_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
{% if item.suggested_price.gross != item.display_price.gross %}
|
||||
{% if event.settings.display_net_prices %}
|
||||
title="{% blocktrans trimmed with item=item.name price=item.display_price.net|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=item.name price=item.display_price.gross|money:event.currency %}Modify price for {{ item }}, at least {{ price }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
{% else %}
|
||||
title="{% blocktrans trimmed with item=item.name %}Modify price for {{ item }}{% endblocktrans %}"
|
||||
{% endif %}
|
||||
value="{% if event.settings.display_net_prices %}{{ item.suggested_price.net|money_numberfield:event.currency }}{% else %}{{ item.suggested_price.gross|money_numberfield:event.currency }}{% endif %}"
|
||||
step="any">
|
||||
</div>
|
||||
<p>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% load i18n %}
|
||||
{% load eventurl %}
|
||||
{% load urlreplace %}
|
||||
{% include "pretixpresale/fragment_event_list_filter.html" with request=request %}
|
||||
<nav aria-label="{% trans "calendar navigation" %}">
|
||||
<ul class="row calendar-nav">
|
||||
<li class="col-sm-4 col-xs-2 text-left flip">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% load i18n %}
|
||||
{% load eventurl %}
|
||||
{% load urlreplace %}
|
||||
{% include "pretixpresale/fragment_event_list_filter.html" with request=request %}
|
||||
<nav aria-label="{% trans "calendar navigation" %}">
|
||||
<ul class="row calendar-nav">
|
||||
<li class="col-sm-4 col-xs-2 text-left flip">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% load i18n %}
|
||||
{% load eventurl %}
|
||||
{% include "pretixpresale/fragment_event_list_filter.html" with request=request %}
|
||||
<ul class="list-unstyled">
|
||||
{% for subev in subevent_list.subevent_list %}
|
||||
<li class="subevent-row">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="subevent" value="{{ subevent.id|default_if_none:"" }}" />
|
||||
<input type="hidden" name="next" value="{{ request.path }}" />
|
||||
<input type="hidden" name="next" value="{% if next_url %}{{ next_url }}{% else %}{{ request.path }}{% endif %}" />
|
||||
<div class="col-md-4 col-sm-6 col-xs-12">
|
||||
<button class="btn btn-block btn-primary" type="submit">
|
||||
{% trans "Redeem voucher" %}
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if subevent and "date" not in request.GET %}
|
||||
{% if subevent and "date" not in request.GET and "filtered" not in request.GET %}
|
||||
<p>
|
||||
{% if show_cart %}
|
||||
<button class="subevent-toggle btn btn-primary btn-block btn-lg" aria-expanded="false">
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
{% trans "Contact information" %}
|
||||
{% endif %}
|
||||
</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</h4>
|
||||
</summary>
|
||||
<div id="invoice" class="panel-collapse">
|
||||
@@ -55,7 +54,6 @@
|
||||
<strong>{{ pos.item.name }}{% if pos.variation %}
|
||||
– {{ pos.variation }}
|
||||
{% endif %}</strong>
|
||||
<i class="fa fa-angle-down collapse-indicator" aria-hidden="true"></i>
|
||||
</h4>
|
||||
</summary>
|
||||
<div id="cp{{ pos.id }}">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user