mirror of
https://github.com/pretix/pretix.git
synced 2026-11-12 01:37:07 +00:00
Compare commits
47
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a2d732925 | ||
|
|
ceff9de5ee | ||
|
|
38b467cef7 | ||
|
|
ae95df7ea2 | ||
|
|
d362f16417 | ||
|
|
7f1a0fd58f | ||
|
|
6d05cfea8b | ||
|
|
c1b8259075 | ||
|
|
e394054ae3 | ||
|
|
dda2a18fdf | ||
|
|
68bd182f79 | ||
|
|
2ee6ea7692 | ||
|
|
a37305f8f4 | ||
|
|
bd4b049c16 | ||
|
|
cb852a8fa7 | ||
|
|
86dd5619e0 | ||
|
|
b1a1d66156 | ||
|
|
e229697d2a | ||
|
|
f9c7378da7 | ||
|
|
86152a182a | ||
|
|
76899600b0 | ||
|
|
04a0b009a6 | ||
|
|
4e9d60d238 | ||
|
|
fe0d0ceb2e | ||
|
|
8457603555 | ||
|
|
ae35af596f | ||
|
|
47c3493372 | ||
|
|
85d65d17b4 | ||
|
|
e50c845e09 | ||
|
|
c84d9061da | ||
|
|
25c9659655 | ||
|
|
b6bce961c3 | ||
|
|
1de0455ebc | ||
|
|
9fdafa57de | ||
|
|
50bcfc8c74 | ||
|
|
fa552fe7d1 | ||
|
|
cbfc24dd64 | ||
|
|
6e0c2d69a5 | ||
|
|
34ed175abe | ||
|
|
a9aaf8638e | ||
|
|
a613affa05 | ||
|
|
cd0ed78b76 | ||
|
|
4889abd75c | ||
|
|
0a73faa8bd | ||
|
|
def5042661 | ||
|
|
e6f8f178af | ||
|
|
5f5380e8b1 |
No files matched your search
@@ -56,7 +56,7 @@ calculated automatically.
|
||||
},
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"datafield": "A1B2C3D4",
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
Cart positions
|
||||
==============
|
||||
|
||||
.. note::
|
||||
|
||||
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Features or fields not yet available are marked with **NEW**.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
The API provides limited access to the cart position data model. This API currently only allows creating and deleting
|
||||
cart positions to reserve quota.
|
||||
|
||||
@@ -31,12 +39,13 @@ voucher integer Internal ID of
|
||||
addon_to integer Internal ID of the position this position is an add-on for (or ``null``)
|
||||
is_bundled boolean If ``addon_to`` is set, this shows whether this is a bundled product or an addon product
|
||||
subevent integer ID of the date inside an event series this position belongs to (or ``null``)
|
||||
answers list of objects Answers to user-defined questions
|
||||
├ question integer Internal ID of the answered question
|
||||
answers list of objects Values of data fields (answers to user-defined questions)
|
||||
├ datafield string **NEW** The data field's ``identifier`` (internal reference)
|
||||
├ answer string Text representation of the answer
|
||||
├ question_identifier string The question's ``identifier`` field
|
||||
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
|
||||
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
|
||||
├ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
|
||||
├ question integer **Deprecated.** Internal ID of the data field
|
||||
└ question_identifier string **Read-only, deprecated.** The data field's ``identifier`` (internal reference)
|
||||
seat objects The assigned seat (or ``null``)
|
||||
├ id integer Internal ID of the seat instance
|
||||
├ name string Human-readable seat name
|
||||
@@ -199,7 +208,8 @@ Cart position endpoints
|
||||
* ``bundled`` (optional, expect a list of nested objects of cart positions)
|
||||
* ``answers``
|
||||
|
||||
* ``question``
|
||||
* ``datafield`` **NEW**
|
||||
* ``question`` **DEPRECATED**
|
||||
* ``answer``
|
||||
* ``options``
|
||||
|
||||
@@ -223,7 +233,7 @@ Cart position endpoints
|
||||
"attendee_email": null,
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"datafield": "A1B2C3D4",
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
@@ -285,7 +295,7 @@ Cart position endpoints
|
||||
"attendee_email": null,
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"datafield": "A1B2C3D4",
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
@@ -303,7 +313,7 @@ Cart position endpoints
|
||||
"attendee_email": null,
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"datafield": "A1B2C3D4",
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
Check-in
|
||||
========
|
||||
|
||||
.. note::
|
||||
|
||||
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Features or fields not yet available are marked with **NEW**.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
This page describes special APIs built for ticket scanning apps. For managing check-in configuration or other operations,
|
||||
please also see :ref:`rest-checkinlists`. The check-in list API also contains endpoints to obtain statistics or log
|
||||
failed scans.
|
||||
@@ -24,41 +32,43 @@ Checking a ticket in
|
||||
passed needs to be from a distinct event.
|
||||
|
||||
:query string expand: Expand a field inside the ``position`` object into a full object. Currently ``subevent``, ``item``, ``variation``, and ``answers.question`` are supported. Can be passed multiple times.
|
||||
:<json string secret: Scanned QR code corresponding to the ``secret`` attribute of a ticket.
|
||||
:<json string source_type: Type of source the ``secret`` was obtained form. Defaults to ``"barcode"``.
|
||||
:<json array lists: List of check-in list IDs to search on. No two check-in lists may be from the same event.
|
||||
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
|
||||
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
|
||||
:<json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
|
||||
:>json string secret: Scanned QR code corresponding to the ``secret`` attribute of a ticket.
|
||||
:>json string source_type: Type of source the ``secret`` was obtained form. Defaults to ``"barcode"``.
|
||||
:>json array lists: List of check-in list IDs to search on. No two check-in lists may be from the same event.
|
||||
:>json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
|
||||
:>json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
|
||||
:>json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
|
||||
questions that have not been filled. This is usually used to upload offline scans that already happened,
|
||||
because there's no point in validating them since they happened whether they are valid or not. Defaults to ``false``.
|
||||
:<json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
|
||||
:>json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
|
||||
you do not implement question handling in your user interface, you **must**
|
||||
set this to ``false``. In that case, questions will just be ignored. Defaults
|
||||
to ``true``.
|
||||
:<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
|
||||
:>json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
|
||||
Defaults to ``false`` and only works when ``include_pending`` is set on the check-in
|
||||
list.
|
||||
:<json object answers: If questions are supported/required, you may/must supply a mapping of question IDs to their
|
||||
respective answers. The answers should always be strings. In case of (multiple-)choice-type
|
||||
:>json object answers: If questions are supported/required, you may/must supply a mapping of ``identifier`` (`internal
|
||||
reference`) of data fields to their respective answers (**NEW**).
|
||||
For backwards compatibility, a mapping of data field ``id`` to answer is supported, as well.
|
||||
The answers should always be strings. In case of (multiple-)choice-type
|
||||
answers, the string should contain the (comma-separated) IDs of the selected options.
|
||||
:<json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
|
||||
:>json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
|
||||
this request twice with the same nonce, the second request will also succeed but will always
|
||||
create only one check-in object even when the previous request was successful as well. This
|
||||
allows for a certain level of idempotency and enables you to re-try after a connection failure.
|
||||
:<json string exchange_medium_type: To perform an exchange to a reusable medium, pass the type of the new reusable medium
|
||||
:<json string exchange_medium_identifier: To perform an exchange to a reusable media, pass the identifier of the new medium
|
||||
:<json boolean use_order_locale: Specifies that pretix should use the customer's language (``locale`` field from the
|
||||
:>json string exchange_medium_type: To perform an exchange to a reusable medium, pass the type of the new reusable medium
|
||||
:>json string exchange_medium_identifier: To perform an exchange to a reusable media, pass the identifier of the new medium
|
||||
:>json boolean use_order_locale: Specifies that pretix should use the customer's language (``locale`` field from the
|
||||
order) when building texts (currently only the ``reason_explanation`` response field).
|
||||
Defaults to ``false`` in which case the server will determine the language (currently
|
||||
the event default language, might change in the future with support for the
|
||||
``Accept-Language`` header).
|
||||
:<json boolean simulate: Do not actually perform the check-in, only simulate the response. The ``position`` response
|
||||
:>json boolean simulate: Do not actually perform the check-in, only simulate the response. The ``position`` response
|
||||
object will not reflect the simulated changes.
|
||||
:>json string status: ``"ok"``, ``"incomplete"``, ``"exchange"``, or ``"error"``
|
||||
:>json string reason: Reason code, only set on status ``"error"``, see below for possible values.
|
||||
:>json string reason_explanation: Human-readable explanation, only set on status ``"error"`` and reason ``"rules"``, can be null.
|
||||
:>json object position: Copy of the matching order position (if any was found). The contents are the same as the
|
||||
:<json string status: ``"ok"``, ``"incomplete"``, ``"exchange"``, or ``"error"``
|
||||
:<json string reason: Reason code, only set on status ``"error"``, see below for possible values.
|
||||
:<json string reason_explanation: Human-readable explanation, only set on status ``"error"`` and reason ``"rules"``, can be null.
|
||||
:<json object position: Copy of the matching order position (if any was found). The contents are the same as the
|
||||
:ref:`order-position-resource`, with the following differences: (1) The ``checkins`` value
|
||||
will only include check-ins for the selected list. (2) An additional boolean property
|
||||
``require_attention`` will inform you whether either the order or the item have the
|
||||
@@ -66,13 +76,13 @@ Checking a ticket in
|
||||
back to values from a parent product or from invoice addresses. (4) Additional properties
|
||||
``order__status``, ``order__valid_if_pending``, ``order__require_approval``, and
|
||||
``order__locale`` are included with details form the order for convenience.
|
||||
:>json boolean require_attention: Whether or not the ``require_attention`` flag is set on the item or order.
|
||||
:>json list checkin_texts: List of additional texts to show to the user.
|
||||
:>json object list: Excerpt of information about the matching :ref:`check-in list <rest-checkinlists>` (if any was found),
|
||||
:<json boolean require_attention: Whether or not the ``require_attention`` flag is set on the item or order.
|
||||
:<json list checkin_texts: List of additional texts to show to the user.
|
||||
:<json object list: Excerpt of information about the matching :ref:`check-in list <rest-checkinlists>` (if any was found),
|
||||
including the attributes ``id``, ``name``, ``event``, ``subevent``, and ``include_pending``.
|
||||
:>json object questions: List of questions to be answered for check-in, only set on status ``"incomplete"``.
|
||||
:>json object media_policy: Reusable media policy (see documentation on items), only set on status ``"exchange"``.
|
||||
:>json object media_type: Reusable media type (see documentation on items), only set on status ``"exchange"``.
|
||||
:<json object questions: List of questions to be answered for check-in, only set on status ``"incomplete"``.
|
||||
:<json object media_policy: Reusable media policy (see documentation on items), only set on status ``"exchange"``.
|
||||
:<json object media_type: Reusable media type (see documentation on items), only set on status ``"exchange"``.
|
||||
|
||||
**Example request**:
|
||||
|
||||
@@ -92,7 +102,7 @@ Checking a ticket in
|
||||
"datetime": null,
|
||||
"questions_supported": true,
|
||||
"answers": {
|
||||
"4": "XS"
|
||||
"A1B2C3D4": "XS"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +328,7 @@ Performing a ticket search
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "A1B2C3D4",
|
||||
"question": 12,
|
||||
"answer": "Foo",
|
||||
"options": []
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
Check-in lists
|
||||
==============
|
||||
|
||||
.. note::
|
||||
|
||||
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Features or fields not yet available are marked with **NEW**.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
@@ -569,6 +577,7 @@ Order position endpoints
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "A1B2C3D4",
|
||||
"question": 12,
|
||||
"answer": "Foo",
|
||||
"options": []
|
||||
@@ -609,27 +618,29 @@ Order position endpoints
|
||||
:query boolean untrusted_input: If set to true, the lookup parameter is **always** interpreted as a ``secret``, never
|
||||
as an ``id``. This should be always set if you are passing through untrusted, scanned
|
||||
data to avoid guessing of ticket IDs.
|
||||
:<json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
|
||||
:>json boolean questions_supported: When this parameter is set to ``true``, handling of questions is supported. If
|
||||
you do not implement question handling in your user interface, you **must**
|
||||
set this to ``false``. In that case, questions will just be ignored. Defaults
|
||||
to ``true``.
|
||||
:<json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
|
||||
:>json boolean canceled_supported: When this parameter is set to ``true``, the response code ``canceled`` may be
|
||||
returned. Otherwise, canceled orders will return ``unpaid``. (**Deprecated**, in
|
||||
the future, this will be ignored and ``canceled`` may always be returned.)
|
||||
:<json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
|
||||
:<json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
|
||||
:>json datetime datetime: Specifies the datetime of the check-in. If not supplied, the current time will be used.
|
||||
:>json boolean force: Specifies that the check-in should succeed regardless of revoked barcode, previous check-ins or required
|
||||
questions that have not been filled. This is usually used to upload offline scans that already happened,
|
||||
because there's no point in validating them since they happened whether they are valid or not. Defaults to ``false``.
|
||||
:<json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
|
||||
:<json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
|
||||
:>json string type: Send ``"exit"`` for an exit and ``"entry"`` (default) for an entry.
|
||||
:>json boolean ignore_unpaid: Specifies that the check-in should succeed even if the order is in pending state.
|
||||
Defaults to ``false`` and only works when ``include_pending`` is set on the check-in
|
||||
list.
|
||||
:<json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
|
||||
:>json string nonce: You can set this parameter to a unique random value to identify this check-in. If you're sending
|
||||
this request twice with the same nonce, the second request will also succeed but will always
|
||||
create only one check-in object even when the previous request was successful as well. This
|
||||
allows for a certain level of idempotency and enables you to re-try after a connection failure.
|
||||
:<json object answers: If questions are supported/required, you may/must supply a mapping of question IDs to their
|
||||
respective answers. The answers should always be strings. In case of (multiple-)choice-type
|
||||
:>json object answers: If questions are supported/required, you may/must supply a mapping of ``identifier`` (`internal
|
||||
reference`) of data fields to their respective answers (**NEW**).
|
||||
For backwards compatibility, a mapping of data field ``id`` to answer is supported, as well.
|
||||
The answers should always be strings. In case of (multiple-)choice-type
|
||||
answers, the string should contain the (comma-separated) IDs of the selected options.
|
||||
|
||||
**Example request**:
|
||||
@@ -648,7 +659,7 @@ Order position endpoints
|
||||
"questions_supported": true,
|
||||
"canceled_supported": true,
|
||||
"answers": {
|
||||
"4": "XS"
|
||||
"A1B2C3D4": "XS"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
|
||||
.. _rest-datafieldoptions:
|
||||
|
||||
Data field options
|
||||
================
|
||||
|
||||
.. note::
|
||||
|
||||
This API is part of an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Until the change, this resource is still available at ``/questions/(id)/options/``.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
:ref:`Data fields <rest-datafields>` of type "choice" or "multiple choice" can have different options attached.
|
||||
|
||||
As with data fields, data field options exist on two resource paths, depending on whether
|
||||
the data field is attached to orders or order positions. Therefore, each endpoint below has two
|
||||
different URLs.
|
||||
|
||||
The options resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the option
|
||||
position integer An integer, used for sorting
|
||||
identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
answer multi-lingual string The displayed value of this option
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/
|
||||
|
||||
Returns a list of all options for a given data field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/11/options/ 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": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 2,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 3,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean active: If set to ``true`` or ``false``, only data fields with this value for the field ``active`` will be
|
||||
returned.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param datafield: The ``id`` field of the data field to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/data field does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(datafield)/options/(id)/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/(id)/
|
||||
|
||||
Returns information on one option, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/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,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param datafield: The ``id`` field of the data field to fetch
|
||||
:param id: The ``id`` field of the option 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)/datafields/position/(datafield)/options/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/
|
||||
|
||||
Create a new option
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/data field to create a option for
|
||||
:param event: The ``slug`` field of the event to create a option for
|
||||
:param datafield: The ``id`` field of the data field to create a option for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The option 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)/datafields/position/(datafield)/options/(id)/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/(id)/
|
||||
|
||||
Update an option. 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.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"position": 3
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
: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 data field to modify
|
||||
:param id: The ``id`` field of the option to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The option 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)/datafields/position/(datafield)/options/(id)/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(datafield)/options/(id)/
|
||||
|
||||
Delete an option.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/options/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 datafield: The ``id`` field of the data field to modify
|
||||
:param id: The ``id`` field of the option 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,428 @@
|
||||
|
||||
.. _rest-datafields:
|
||||
|
||||
Data fields
|
||||
=========
|
||||
|
||||
.. note::
|
||||
|
||||
This API is part of an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Until the change, please keep using the endpoints at ``/questions/``.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Data fields define additional fields related to an order or an order position.
|
||||
By referencing data fields in a questionnaire, you can have customers or staff fill them out -- during or
|
||||
after checkout (web or POS), during check-in in the ticket scanner app, or in the backend.
|
||||
|
||||
There are two different resource paths for data fields, depending on whether the data field is attached
|
||||
to orders or order positions. Therefore, each endpoint below has two different URLs.
|
||||
|
||||
The data field resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the data field
|
||||
internal_name string **Required.** An internal field label
|
||||
identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
Must be unique per event, across all types of data fields.
|
||||
type string **Required.** The expected type of data. Valid options:
|
||||
|
||||
* ``N`` – number
|
||||
* ``S`` – one-line string
|
||||
* ``T`` – multi-line string
|
||||
* ``B`` – boolean
|
||||
* ``C`` – choice from a list
|
||||
* ``M`` – multiple choice from a list
|
||||
* ``F`` – file upload
|
||||
* ``D`` – date
|
||||
* ``H`` – time
|
||||
* ``W`` – date and time
|
||||
* ``CC`` – country code (ISO 3666-1 alpha-2)
|
||||
* ``TEL`` – telephone number
|
||||
show_during_checkin boolean If ``true``, the value of the data field will be shown
|
||||
during check-in (if the check-in client supports it).
|
||||
*Only supported on per-position data fields.*
|
||||
print_on_invoice boolean If ``true``, the data field will be shown on
|
||||
invoices.
|
||||
*Only supported on per-position data fields.*
|
||||
print_on_invoice_label multi-lingual string **Required if ``print_on_invoice`` is ``true``.** Label
|
||||
to print on the invoice before the value of this field.
|
||||
Otherwise `null`.
|
||||
options list of objects In case of data field type ``C`` or ``M``, this lists the
|
||||
available objects. Only writable during creation,
|
||||
use :ref:`separate endpoint <rest-datafieldoptions>` to modify this later.
|
||||
├ id integer Internal ID of the option
|
||||
├ position integer An integer, used for sorting
|
||||
├ identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
└ answer multi-lingual string The displayed value of this option
|
||||
valid_number_min string Minimum value for number fields (optional)
|
||||
valid_number_max string Maximum value for number fields (optional)
|
||||
valid_date_min date Minimum value for date fields (optional)
|
||||
valid_date_max date Maximum value for date fields (optional)
|
||||
valid_datetime_min datetime Minimum value for date and time fields (optional)
|
||||
valid_datetime_max datetime Maximum value for date and time fields (optional)
|
||||
valid_file_portrait boolean Turn on file validation for portrait photos
|
||||
valid_string_length_min integer Minimum length for string fields (optional)
|
||||
valid_string_length_max integer Maximum length for string fields (optional)
|
||||
referenced_by_questionnaires list of integers **Read-only.** List of questionnaire IDs that reference
|
||||
this data field
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/
|
||||
|
||||
Returns a list of all data fields within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/ 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,
|
||||
"internal_name": "T-Shirt size",
|
||||
"type": "C",
|
||||
"identifier": "WY3TP9SL",
|
||||
"show_during_checkin": false,
|
||||
"print_on_invoice": false,
|
||||
"print_on_invoice_label": null,
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"valid_string_length_min": null,
|
||||
"valid_string_length_max": null,
|
||||
"valid_file_portrait": false,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 0,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 1,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 2,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
],
|
||||
"referenced_by_questionnaires": [1]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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`` and ``position``.
|
||||
Default: ``position``
|
||||
:query string identifier: Only return questions with the given identifier string
|
||||
:query boolean ask_during_checkin: Only return questions that are or are not to be asked during check-in
|
||||
:query boolean required: Only return questions that are or are not required to fill in
|
||||
: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)/datafields/position/(id)/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(id)/
|
||||
|
||||
Returns information on one data field, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/datafields/position/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,
|
||||
"internal_name": "T-Shirt size",
|
||||
"type": "C",
|
||||
"identifier": "WY3TP9SL",
|
||||
"show_during_checkin": false,
|
||||
"print_on_invoice": false,
|
||||
"print_on_invoice_label": null,
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"valid_string_length_min": null,
|
||||
"valid_string_length_max": null,
|
||||
"valid_file_portrait": false,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 0,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 1,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 2,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
],
|
||||
"referenced_by_questionnaires": [1]
|
||||
}
|
||||
|
||||
: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 question 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)/datafields/position/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/
|
||||
|
||||
Create a new question
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/datafields/position/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"internal_name": "T-Shirt size",
|
||||
"type": "C",
|
||||
"show_during_checkin": false,
|
||||
"print_on_invoice": false,
|
||||
"print_on_invoice_label": null,
|
||||
"options": [
|
||||
{
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"internal_name": "T-Shirt size",
|
||||
"type": "C",
|
||||
"identifier": "WY3TP9SL",
|
||||
"show_during_checkin": false,
|
||||
"print_on_invoice": false,
|
||||
"print_on_invoice_label": null,
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"valid_string_length_min": null,
|
||||
"valid_string_length_max": null,
|
||||
"valid_file_portrait": false,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 0,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 1,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 2,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
],
|
||||
"referenced_by_questionnaires": [1]
|
||||
}
|
||||
|
||||
: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)/datafields/position/(id)/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(id)/
|
||||
|
||||
Update a data field. 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.
|
||||
|
||||
You can change all fields of the resource except the ``options`` field. If
|
||||
you need to update/delete options please use the nested dedicated endpoints.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/datafields/position/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"internal_name": "Clothing size"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"internal_name": "Clothing size",
|
||||
"type": "C",
|
||||
"identifier": "WY3TP9SL",
|
||||
"show_during_checkin": false,
|
||||
"print_on_invoice": false,
|
||||
"print_on_invoice_label": null,
|
||||
"valid_number_min": null,
|
||||
"valid_number_max": null,
|
||||
"valid_date_min": null,
|
||||
"valid_date_max": null,
|
||||
"valid_datetime_min": null,
|
||||
"valid_datetime_max": null,
|
||||
"valid_string_length_min": null,
|
||||
"valid_string_length_max": null,
|
||||
"valid_file_portrait": false,
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 0,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 1,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 2,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
],
|
||||
"referenced_by_questionnaires": [1]
|
||||
}
|
||||
|
||||
: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 question to modify
|
||||
:statuscode 200: no error
|
||||
: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.
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/datafields/position/(id)/
|
||||
/api/v1/organizers/(organizer)/events/(event)/datafields/order/(id)/
|
||||
|
||||
Delete a data field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/datafields/position/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 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.
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ at :ref:`plugin-docs`.
|
||||
item_add-ons
|
||||
item_meta_properties
|
||||
item_program_times
|
||||
datafields
|
||||
datafield_options
|
||||
questionnaires
|
||||
questions
|
||||
question_options
|
||||
quotas
|
||||
|
||||
@@ -37,12 +37,9 @@ tax_rule integer The internal
|
||||
admission boolean ``true`` for items that grant admission to the event
|
||||
(such as primary tickets) and ``false`` for others
|
||||
(such as add-ons or merchandise).
|
||||
personalized boolean ``true`` for items that require personalization according
|
||||
personalized boolean **DEPRECATED.** ``true`` for items that require personalization according
|
||||
to event settings. Only affects system-level fields, not
|
||||
custom questions. Currently only allowed for products with
|
||||
``admission`` set to ``true``. For backwards compatibility,
|
||||
when creating new items and this field is not given, it defaults
|
||||
to the same value as ``admission``.
|
||||
custom questions. Defaults to ``false``.
|
||||
position integer An integer, used for sorting
|
||||
picture file A product picture to be displayed in the shop
|
||||
(can be ``null``).
|
||||
@@ -233,6 +230,17 @@ meta_data object Values set fo
|
||||
|
||||
The ``program_times`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2027.1
|
||||
|
||||
The ``personalized`` attribute has been deprecated.
|
||||
|
||||
For compatibility with existing applications:
|
||||
|
||||
* When retrieving products, `personalized` is `True` if any attached questionnaire asks for `attendee_name` and/or `attendee_email`.
|
||||
* When creating a new product, setting the `personalized` field to `True` will attach the "Attendee data" questionnaire to the new product. If no such questionnaire exists, it will be created.
|
||||
Before, the `personalized` field defaulted to the same value as `admission`. Now, it defaults to `false`.
|
||||
* When updating a product, the `personalized` field cannot be changed, returning an HTTP 400 error if attempted.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
Orders
|
||||
======
|
||||
|
||||
.. note::
|
||||
|
||||
This API is affected by an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Features or fields not yet available are marked with **NEW**.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
Order resource
|
||||
--------------
|
||||
|
||||
@@ -119,6 +127,11 @@ cancellation_date datetime Time of order c
|
||||
plugin_data object Additional data added by plugins.
|
||||
use_gift_cards list of strings List of unique gift card secrets that are used to pay
|
||||
for this order.
|
||||
answers list of objects **NEW** Values of data fields (answers to user-defined questions)
|
||||
├ datafield string The data field's ``identifier`` (internal reference)
|
||||
├ answer string Text representation of the answer
|
||||
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
|
||||
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
@@ -162,6 +175,10 @@ use_gift_cards list of strings List of unique
|
||||
|
||||
The ``use_gift_cards`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2027.1
|
||||
|
||||
The ``answers`` attribute has been added.
|
||||
|
||||
.. _order-position-resource:
|
||||
|
||||
Order position resource
|
||||
@@ -231,12 +248,13 @@ print_logs list of objects List of print j
|
||||
downloads list of objects List of ticket download options
|
||||
├ output string Ticket output provider (e.g. ``pdf``, ``passbook``)
|
||||
└ url string Download URL
|
||||
answers list of objects Answers to user-defined questions
|
||||
├ question integer Internal ID of the answered question
|
||||
├ answer string Text representation of the answer (URL if answer is a file)
|
||||
├ question_identifier string The question's ``identifier`` field
|
||||
answers list of objects Values of data fields (answers to user-defined questions)
|
||||
├ datafield string **NEW** The data field's ``identifier`` (internal reference)
|
||||
├ answer string Text representation of the answer
|
||||
├ options list of integers Internal IDs of selected option(s)s (only for choice types)
|
||||
└ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
|
||||
├ option_identifiers list of strings The ``identifier`` fields of the selected option(s)s
|
||||
├ question integer **Deprecated.** Internal ID of the data field
|
||||
└ question_identifier string **Read-only, deprecated.** The data field's ``identifier`` (internal reference)
|
||||
seat objects The assigned seat. Can be ``null``.
|
||||
├ id integer Internal ID of the seat instance
|
||||
├ name string Human-readable seat name
|
||||
@@ -452,10 +470,11 @@ List of all orders
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "WY3TP9SL",
|
||||
"question": 12,
|
||||
"question_identifier": "WY3TP9SL",
|
||||
"answer": "Foo",
|
||||
"option_idenfiters": [],
|
||||
"option_identifiers": [],
|
||||
"options": []
|
||||
}
|
||||
],
|
||||
@@ -488,7 +507,15 @@ List of all orders
|
||||
],
|
||||
"refunds": [],
|
||||
"cancellation_date": null,
|
||||
"plugin_data": {}
|
||||
"plugin_data": {},
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "XYZ12345",
|
||||
"answer": "42",
|
||||
"option_identifiers": [],
|
||||
"options": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -699,6 +726,7 @@ Fetching individual orders
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "WY3TP9SL",
|
||||
"question": 12,
|
||||
"question_identifier": "WY3TP9SL",
|
||||
"answer": "Foo",
|
||||
@@ -735,7 +763,15 @@ Fetching individual orders
|
||||
],
|
||||
"refunds": [],
|
||||
"cancellation_date": null,
|
||||
"plugin_data": {}
|
||||
"plugin_data": {},
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "XYZ12345",
|
||||
"answer": "42",
|
||||
"option_identifiers": [],
|
||||
"options": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
@@ -1079,7 +1115,8 @@ Creating orders
|
||||
* ``discount`` (optional, only possible if ``price`` is set; attention: if this is set to not-``null`` on any position, automatic calculation of discounts will not run)
|
||||
* ``answers``
|
||||
|
||||
* ``question``
|
||||
* ``datafield`` (**NEW**)
|
||||
* ``question`` (**DEPRECATED**)
|
||||
* ``answer``
|
||||
* ``options``
|
||||
|
||||
@@ -1114,6 +1151,12 @@ Creating orders
|
||||
order isn't completely paid after its creation with ``use_gift_cards``, then a subsequent request to the payment
|
||||
endpoint is needed.
|
||||
|
||||
* **NEW** ``answers`` (optional). Values for order-level data fields.
|
||||
|
||||
* ``datafield``
|
||||
* ``answer``
|
||||
* ``options``
|
||||
|
||||
If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually
|
||||
to incrementing integers starting with ``1``. Then, you can reference one of these
|
||||
IDs in the ``addon_to`` field of another position. Note that all add_ons for a specific position need to come
|
||||
@@ -1161,6 +1204,12 @@ Creating orders
|
||||
"internal_reference": "",
|
||||
"vat_id": ""
|
||||
},
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "XYZ12345",
|
||||
"answer": "42"
|
||||
}
|
||||
],
|
||||
"positions": [
|
||||
{
|
||||
"positionid": 1,
|
||||
@@ -1174,7 +1223,7 @@ Creating orders
|
||||
"addon_to": null,
|
||||
"answers": [
|
||||
{
|
||||
"question": 1,
|
||||
"datafield": "WY3TP9SL",
|
||||
"answer": "23",
|
||||
"options": []
|
||||
}
|
||||
@@ -1684,6 +1733,7 @@ List of all order positions
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "WY3TP9SL",
|
||||
"question": 12,
|
||||
"question_identifier": "WY3TP9SL",
|
||||
"answer": "Foo",
|
||||
@@ -1863,6 +1913,7 @@ Fetching individual positions
|
||||
],
|
||||
"answers": [
|
||||
{
|
||||
"datafield": "WY3TP9SL",
|
||||
"question": 12,
|
||||
"question_identifier": "WY3TP9SL",
|
||||
"answer": "Foo",
|
||||
@@ -1971,7 +2022,7 @@ Manipulating individual positions
|
||||
|
||||
* ``answers``: If specified, you will need to provide **all** answers for this order position.
|
||||
Validation is handled the same way as when creating orders through the API. You are therefore
|
||||
expected to provide ``question``, ``answer``, and possibly ``options``. ``question_identifier``
|
||||
expected to provide ``datafield``, ``answer``, and possibly ``options``. ``question`` is deprecated. ``question_identifier``
|
||||
and ``option_identifiers`` will be ignored. As a special case, you can submit the magic value
|
||||
``"file:keep"`` as the answer to a file question to keep the current value without re-uploading it.
|
||||
|
||||
@@ -2067,7 +2118,7 @@ Manipulating individual positions
|
||||
* ``state``
|
||||
|
||||
* ``answers``: Validation is handled the same way as when creating orders through the API. You are therefore
|
||||
expected to provide ``question``, ``answer``, and possibly ``options``. ``question_identifier``
|
||||
expected to provide ``datafield``, ``answer``, and possibly ``options``. ``question`` is deprecated. ``question_identifier``
|
||||
and ``option_identifiers`` will be ignored. As a special case, you can submit the magic value
|
||||
``"file:keep"`` as the answer to a file question to keep the current value without re-uploading it.
|
||||
|
||||
|
||||
@@ -1,229 +1,7 @@
|
||||
Question options
|
||||
================
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
.. warning:: This resource is **deprecated**.
|
||||
|
||||
Questions of type "choice" or "multiple choice" can have different options attached.
|
||||
The options resource contains the following public fields:
|
||||
New applications must use the :ref:`rest-datafieldoptions` resource.
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the option
|
||||
position integer An integer, used for sorting
|
||||
identifier string An arbitrary string that can be used for matching with
|
||||
other sources.
|
||||
answer multi-lingual string The displayed value of this option
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/
|
||||
|
||||
Returns a list of all options for a given question.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questions/11/options/ 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": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"identifier": "DFEMJWMJ",
|
||||
"position": 2,
|
||||
"answer": {"en": "M"}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"identifier": "W9AH7RDE",
|
||||
"position": 3,
|
||||
"answer": {"en": "L"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||
:query boolean active: If set to ``true`` or ``false``, only questions with this value for the field ``active`` will be
|
||||
returned.
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param question: The ``id`` field of the question to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event/question does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questions/(question)/options/(id)/
|
||||
|
||||
Returns information on one option, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/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,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:param question: The ``id`` field of the question to fetch
|
||||
:param id: The ``id`` field of the option 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)/questions/(question)/options/
|
||||
|
||||
Creates a new option
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event/question to create a option for
|
||||
:param event: The ``slug`` field of the event to create a option for
|
||||
:param question: The ``id`` field of the question to create a option for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The option 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)/questions/(question)/options/(id)/
|
||||
|
||||
Update an option. 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.
|
||||
|
||||
You can change all fields of the resource except the ``id`` field.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/1/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
Content-Length: 94
|
||||
|
||||
{
|
||||
"position": 3
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"identifier": "LVETRWVU",
|
||||
"position": 1,
|
||||
"answer": {"en": "S"}
|
||||
}
|
||||
|
||||
: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 question to modify
|
||||
:param id: The ``id`` field of the option to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The option 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)/questions/(id)/options/(id)/
|
||||
|
||||
Delete an option.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/questions/1/options/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 question to modify
|
||||
:param id: The ``id`` field of the option 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,379 @@
|
||||
|
||||
.. _rest-questionnaires:
|
||||
|
||||
Questionnaires
|
||||
=========
|
||||
|
||||
.. note::
|
||||
|
||||
This API is part of an upcoming larger change to our API. The API documentation already reflects the future
|
||||
version. Until the change, please keep using the endpoints at ``/questions/``.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
Questionnaires are attached to one or more products, and a product can have multiple questionnaires.
|
||||
They consist of questionnaire rows, each of which can be one of the following:
|
||||
|
||||
Reference to system field
|
||||
To reference a system field, use one of the identifier strings from the table below in the row's `datafield` attribute.
|
||||
Currently, system fields are only defined on order positions, not on orders.
|
||||
|
||||
=============== =========================== ============================
|
||||
Container Identifier Label
|
||||
=============== =========================== ============================
|
||||
Order position `"@attendee_name_parts"` Attendee name
|
||||
Order position `"@attendee_email"` Attendee email
|
||||
Order position `"@company"` Company
|
||||
Order position `"@street"` Street
|
||||
Order position `"@zipcode"` ZIP code
|
||||
Order position `"@city"` City
|
||||
Order position `"@state"` State
|
||||
Order position `"@country"` Country
|
||||
=============== =========================== ============================
|
||||
|
||||
|
||||
Reference to user-defined data field
|
||||
To reference a :ref:`user-defined data field <rest-datafields>`, use its internal reference (`identifier`)
|
||||
in the row's `datafield` attribute.
|
||||
|
||||
|
||||
Static explanation text / subheading
|
||||
To add a static text block, set the row's `datafield` attribute to `null`. In this case, the text
|
||||
from the `label` attribute is displayed as a subheading, and the `help_text` attribute as a normal paragraph.
|
||||
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
id integer Internal ID of the questionnaire
|
||||
type string The type of questionnaire. Valid options:
|
||||
|
||||
* ``order_purchase`` — Order-wide, before purchase
|
||||
* ``position_purchase`` — Per product, before purchase
|
||||
* ``position_attendee`` — Per product, via attendee link
|
||||
* ``position_checkin`` — Per product, at check-in
|
||||
* ``position_hidden`` — Per product, hidden
|
||||
internal_name string Internal label for the questionnaire.
|
||||
items list of integers List of item IDs this questionnaire is assigned to.
|
||||
*Only supported on per-product questionnaires.*
|
||||
position integer An integer, used for sorting
|
||||
all_sales_channels boolean If ``true`` (default), the questions from this questionnaire
|
||||
are asked on all sales channels.
|
||||
limit_sales_channels list of strings List of sales channel identifiers the questions are asked on
|
||||
if ``all_sales_channels`` is ``false``.
|
||||
rows list of objects List of all questionnaire rows.
|
||||
├ datafield string Reference to a data field (see above)
|
||||
├ required boolean If ``true``, the question needs to be filled out.
|
||||
├ label multi-lingual string The field label shown to the customer. In case of a static
|
||||
text block, the subheading.
|
||||
├ help_text multi-lingual string The help text shown to the customer.
|
||||
├ dependency_datafield string ``datafield`` reference of a different row in the same
|
||||
questionnaire.
|
||||
The current question will only be shown if the question
|
||||
given in this attribute is set to one of the values given
|
||||
in ``dependency_values``.
|
||||
├ dependency_values list of strings If ``dependency_datafield`` is set to reference a boolean
|
||||
data field, this should be ``["True"]`` or ``["False"]``.
|
||||
Otherwise, it should be a list of ``identifier`` values
|
||||
of question options.
|
||||
├ rendered_help_text string **Read-only.** Markdown contents from help_text rendered
|
||||
to HTML
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/questionnaires/
|
||||
|
||||
Returns a list of all questionnaires within a given event.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questionnaires/ 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": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "position_purchase",
|
||||
"internal_name": "Attendee data",
|
||||
"items": [1, 2],
|
||||
"position": 0,
|
||||
"all_sales_channels": true,
|
||||
"limit_sales_channels": [],
|
||||
"rows": [
|
||||
{
|
||||
"datafield": "@attendee_name_parts",
|
||||
"required": false,
|
||||
"label": {"en": "Attendee name"},
|
||||
"help_text": {},
|
||||
"dependency_datafield": null,
|
||||
"dependency_values": [],
|
||||
"rendered_help_text": ""
|
||||
},
|
||||
{
|
||||
"datafield": "@attendee_email",
|
||||
"required": false,
|
||||
"label": {"en": "Attendee email"},
|
||||
"help_text": {"en": "*We'll send you our program guide a few days before the event.*"},
|
||||
"dependency_datafield": null,
|
||||
"dependency_values": [],
|
||||
"rendered_help_text": "<em>We'll send you our program guide a few days before the event.</em>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "order_purchase",
|
||||
"internal_name": "Per-order questions",
|
||||
"items": [],
|
||||
"position": 0,
|
||||
"all_sales_channels": true,
|
||||
"limit_sales_channels": [],
|
||||
"rows": [
|
||||
{
|
||||
"datafield": "87Y8DCS9",
|
||||
"required": false,
|
||||
"label": {"en": "How did you find us?"},
|
||||
"help_text": {},
|
||||
"dependency_datafield": null,
|
||||
"dependency_values": [],
|
||||
"rendered_help_text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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`` and ``position``.
|
||||
Default: ``position``
|
||||
:query string type: Only return questionnaires with the given type
|
||||
:query string items: Only return questionnaires associated with the given item (internal item ID)
|
||||
:query boolean sales_channel: Only return questionnaires visible on the given sales channel (sales channel identifier string)
|
||||
: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)/questionnaires/(id)/
|
||||
|
||||
Returns information on one questionnaire, identified by its ID.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/sampleconf/questionnaires/2/ 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": 2,
|
||||
"type": "order_purchase",
|
||||
"internal_name": "Per-order questions",
|
||||
"items": [],
|
||||
"position": 0,
|
||||
"all_sales_channels": true,
|
||||
"limit_sales_channels": [],
|
||||
"rows": [
|
||||
{
|
||||
"datafield": "87Y8DCS9",
|
||||
"required": false,
|
||||
"label": {"en": "How did you find us?"},
|
||||
"help_text": {},
|
||||
"dependency_datafield": null,
|
||||
"dependency_values": [],
|
||||
"rendered_help_text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
: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 questionnaire 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)/questionnaires/
|
||||
|
||||
Create a new questionnaire
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/questionnaires/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"type": "order_purchase",
|
||||
"internal_name": "Per-order questions",
|
||||
"position": 0,
|
||||
"all_sales_channels": true,
|
||||
"rows": [
|
||||
{
|
||||
"datafield": "87Y8DCS9",
|
||||
"required": false,
|
||||
"label": {"en": "How did you find us?"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 201 Created
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"type": "order_purchase",
|
||||
"internal_name": "Per-order questions",
|
||||
"items": [],
|
||||
"position": 0,
|
||||
"all_sales_channels": true,
|
||||
"limit_sales_channels": [],
|
||||
"rows": [
|
||||
{
|
||||
"datafield": "87Y8DCS9",
|
||||
"required": false,
|
||||
"label": {"en": "How did you find us?"},
|
||||
"help_text": {},
|
||||
"dependency_datafield": null,
|
||||
"dependency_values": [],
|
||||
"rendered_help_text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the event to create a questionnaire for
|
||||
:param event: The ``slug`` field of the event to create a questionnaire for
|
||||
:statuscode 201: no error
|
||||
:statuscode 400: The questionnaire 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)/questionnaires/(id)/
|
||||
|
||||
Update a questionnaire. 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.
|
||||
|
||||
You can only change all ``rows`` en bloc, or keep all of them unchanged in case of a ``PATCH``. If you
|
||||
change ``rows``, you need to specify all fields of the resource.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
PATCH /api/v1/organizers/bigevents/events/sampleconf/questionnaires/2/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"internal_name": "Questions asked per order"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"type": "order_purchase",
|
||||
"internal_name": "Questions asked per order",
|
||||
"items": [],
|
||||
"position": 0,
|
||||
"all_sales_channels": true,
|
||||
"limit_sales_channels": [],
|
||||
"rows": [
|
||||
{
|
||||
"datafield": "87Y8DCS9",
|
||||
"required": false,
|
||||
"label": {"en": "How did you find us?"},
|
||||
"help_text": {},
|
||||
"dependency_datafield": null,
|
||||
"dependency_values": [],
|
||||
"rendered_help_text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer of the questionnaire to modify
|
||||
:param event: The ``slug`` field of the event of the questionnaire to modify
|
||||
:param id: The ``id`` field of the questionnaire to modify
|
||||
:statuscode 200: no error
|
||||
:statuscode 400: The questionnaire 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)/questionnaires/(id)/
|
||||
|
||||
Delete a questionnaire.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
DELETE /api/v1/organizers/bigevents/events/sampleconf/questionnaires/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 of the questionnaire to modify
|
||||
:param event: The ``slug`` field of the event of the questionnaire to modify
|
||||
:param id: The ``id`` field of the questionnaire 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.
|
||||
@@ -8,10 +8,23 @@
|
||||
Questions
|
||||
=========
|
||||
|
||||
.. warning:: This resource is **deprecated**. It is only provided for compatibility with existing applications
|
||||
and should not be used in new development.
|
||||
|
||||
New applications must use the :ref:`rest-datafields` and :ref:`rest-questionnaires` resources.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted pretix with
|
||||
version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
|
||||
This resource will continue to work in read-only mode on events where the
|
||||
:ref:`questionnaire configuration <rest-questionnaires>` is compatible with the old data model.
|
||||
If incompatible configuration is detected, all endpoints return HTTP 410.
|
||||
|
||||
|
||||
Resource description
|
||||
--------------------
|
||||
|
||||
Questions define additional fields that need to be filled out by customers during checkout.
|
||||
Questions define additional fields related to an order position that need to be filled out by customers during checkout.
|
||||
The question resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
@@ -84,6 +97,10 @@ dependency_value string An old version
|
||||
|
||||
The ``show_during_checkin`` attribute has been added.
|
||||
|
||||
.. versionchanged:: 2026.[TODO]
|
||||
|
||||
The questions resource was deprecated and replaced by the :ref:`rest-datafields` and :ref:`rest-questionnaires` resources.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -249,6 +266,13 @@ Endpoints
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/questions/
|
||||
|
||||
.. warning:: This endpoint is **deprecated** and will be removed as part of an upcoming API change.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted
|
||||
pretix with version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
After the change, instead create a :ref:`data field <rest-datafields>` first, then add
|
||||
it to a :ref:`questionnaire <rest-questionnaires>`.
|
||||
|
||||
Creates a new question
|
||||
|
||||
**Example request**:
|
||||
@@ -351,6 +375,13 @@ Endpoints
|
||||
|
||||
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/
|
||||
|
||||
.. warning:: This endpoint is **deprecated** and will be removed as part of an upcoming API change.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted
|
||||
pretix with version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
After the change, instead update the relevant :ref:`data field <rest-datafields>`, or
|
||||
the reference to it inside a :ref:`questionnaire <rest-questionnaires>`.
|
||||
|
||||
Update a question. 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.
|
||||
@@ -437,6 +468,14 @@ Endpoints
|
||||
|
||||
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/questions/(id)/
|
||||
|
||||
|
||||
.. warning:: This endpoint is **deprecated** and will be removed as part of an upcoming API change.
|
||||
The new version is expected to be released for hosted pretix early December and for self-hosted
|
||||
pretix with version 2027.1.
|
||||
You can find more information `on our blog <https://pretix.eu/about/en/blog/20261110-questionnaires/>`_.
|
||||
After the change, insteadremove the questionnaire child from its :ref:`questionnaire <rest-questionnaires>`,
|
||||
or delete the relevant :ref:`data field <rest-datafields>`.
|
||||
|
||||
Delete a question.
|
||||
|
||||
**Example request**:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
sphinx==9.1.*
|
||||
sphinx==9.0.*
|
||||
sphinx-rtd-theme~=3.1.0
|
||||
sphinxcontrib-httpdomain~=2.1.0
|
||||
sphinxcontrib-images~=1.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-e ../
|
||||
sphinx==9.1.*
|
||||
sphinx==9.0.*
|
||||
sphinx-rtd-theme~=3.1.0
|
||||
sphinxcontrib-httpdomain~=2.1.0
|
||||
sphinxcontrib-images~=1.0.1
|
||||
|
||||
+13
-16
@@ -27,16 +27,16 @@ classifiers = [
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"arabic-reshaper==3.0.1", # Support for Arabic in reportlab
|
||||
"arabic-reshaper==3.1.0", # Support for Arabic in reportlab
|
||||
"babel",
|
||||
"BeautifulSoup4==4.15.*",
|
||||
"bleach==6.4.*",
|
||||
"celery==5.6.*",
|
||||
"chardet==5.2.*",
|
||||
"cryptography>=50.0.2",
|
||||
"css-inline==0.22.*",
|
||||
"css-inline==0.23.*",
|
||||
"defusedcsv>=3.0.0",
|
||||
"dnspython==2.*",
|
||||
"dnspython==2.9.*",
|
||||
"Django[argon2]==5.2.*,>=5.2.17",
|
||||
"django-bootstrap3==26.3",
|
||||
"django-compressor==4.6.0",
|
||||
@@ -46,7 +46,7 @@ dependencies = [
|
||||
"django-formtools==2.7",
|
||||
"django-hierarkey==2.0.*,>=2.0.2",
|
||||
"django-hijack==3.7.*",
|
||||
"django-i18nfield==1.11.*",
|
||||
"django-i18nfield==1.12.*",
|
||||
"django-libsass==0.9",
|
||||
"django-localflavor==5.1",
|
||||
"django-markup",
|
||||
@@ -58,17 +58,14 @@ dependencies = [
|
||||
"django-scopes==2.1.*",
|
||||
"django-statici18n==2.8.*",
|
||||
"djangorestframework>=3.18.3",
|
||||
"dnspython==2.8.*",
|
||||
"drf_ujson2==1.7.*",
|
||||
"geoip2==5.*",
|
||||
"importlib_metadata==9.*", # Polyfill, we can probably drop this once we require Python 3.10+
|
||||
"isoweek",
|
||||
"jsonschema",
|
||||
"kombu==5.6.*",
|
||||
"libsass==0.23.*",
|
||||
"lxml",
|
||||
"markdown==3.11.2", # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3.
|
||||
# We can upgrade markdown again once django-bootstrap3 upgrades or once we drop Python 3.6 and 3.7
|
||||
"markdown==3.11.2",
|
||||
"mt-940==4.30.*",
|
||||
"oauthlib==3.3.*",
|
||||
"openpyxl==3.1.*",
|
||||
@@ -82,23 +79,23 @@ dependencies = [
|
||||
"protobuf==7.36.*",
|
||||
"psycopg2-binary",
|
||||
"pycountry",
|
||||
"pycparser==3.11",
|
||||
"pycparser==3.12",
|
||||
"pycryptodome==3.24.*",
|
||||
"pypdf==6.20.*",
|
||||
"python-bidi==0.6.*", # Support for Arabic in reportlab
|
||||
"python-dateutil==3.0.*",
|
||||
"python-dateutil==4.0.*",
|
||||
"pytz",
|
||||
"pytz-deprecation-shim==0.1.*",
|
||||
"pyuca",
|
||||
"qrcode==8.2",
|
||||
"redis==7.4.*",
|
||||
"reportlab==5.0.*",
|
||||
"reportlab==5.1.*",
|
||||
"requests==2.34.*",
|
||||
"sentry-sdk==2.71.*",
|
||||
"sepaxml==2.7.*",
|
||||
"stripe==7.9.*",
|
||||
"text-unidecode==1.*",
|
||||
"tlds>=2026093003",
|
||||
"tlds>=2026102900",
|
||||
"tqdm==4.*",
|
||||
"ua-parser==1.0.*",
|
||||
"vobject==0.9.*",
|
||||
@@ -112,17 +109,17 @@ dev = [
|
||||
"aiohttp==3.14.*",
|
||||
"coverage",
|
||||
"coveralls",
|
||||
"fakeredis==2.39.*",
|
||||
"flake8==7.4.*",
|
||||
"fakeredis==2.40.*",
|
||||
"flake8==7.5.*",
|
||||
"freezegun",
|
||||
"isort==9.0.*",
|
||||
"pep8-naming==0.15.*",
|
||||
"potypo",
|
||||
"pytest-asyncio>=1.4.0",
|
||||
"pytest-asyncio>=1.4.1.post1",
|
||||
"pytest-cache",
|
||||
"pytest-cov",
|
||||
"pytest-django==4.*",
|
||||
"pytest-mock==3.16.*",
|
||||
"pytest-mock==3.17.*",
|
||||
"pytest-sugar",
|
||||
"pytest-xdist==3.8.*",
|
||||
"pytest-playwright",
|
||||
|
||||
@@ -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__ = "2026.9.0"
|
||||
__version__ = "2026.10.0.dev0"
|
||||
@@ -117,6 +117,7 @@ class TransmissionInfoSerializer(serializers.Serializer):
|
||||
super().__init__(*args, **kwargs)
|
||||
for k, v in transmission_type.invoice_address_form_fields.items():
|
||||
self.fields[k] = form_field_to_serializer_field(v)
|
||||
self.fields[k].required = False # invoice_address_form_fields_required is checked by parent serializer
|
||||
|
||||
|
||||
class InvoiceAddressSerializer(I18nAwareModelSerializer):
|
||||
|
||||
@@ -264,6 +264,8 @@ def oidc_validate_authorization(provider, code, redirect_uri, pkce_code_verifier
|
||||
)
|
||||
)
|
||||
|
||||
profile['oidc_claims'] = userinfo
|
||||
|
||||
return profile
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ from typing import List, Optional, Protocol
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import DatabaseError, transaction
|
||||
from django.utils.functional import classproperty
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
@@ -101,9 +102,8 @@ class OutboundSyncProvider:
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.close()
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def display_name(cls):
|
||||
@classproperty
|
||||
def display_name(cls): # noqa: N805
|
||||
return str(cls.identifier)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -131,6 +131,27 @@ class PeppolIdValidator:
|
||||
def __init__(self, validate_online=False):
|
||||
self.validate_online = validate_online
|
||||
|
||||
def _validate_peppol_id_online(self, value):
|
||||
base_hostnames = ['participant.sml.prod.tech.peppol.org', 'participant.sml.test.tech.peppol.org']
|
||||
smp_id = base64.b32encode(hashlib.sha256(value.lower().encode()).digest()).decode().rstrip("=")
|
||||
for base_hostname in base_hostnames:
|
||||
smp_domain = f'{smp_id}.iso6523-actorid-upis.{base_hostname}'
|
||||
resolver = dns.resolver.Resolver()
|
||||
try:
|
||||
answers = resolver.resolve(smp_domain, 'NAPTR', lifetime=1.0)
|
||||
if answers:
|
||||
return value
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
# ID not registered, do not set found=True
|
||||
pass
|
||||
except Exception: # noqa
|
||||
# Error likely on our end or infrastructure is down, allow user to proceed
|
||||
return value
|
||||
|
||||
raise ValidationError(
|
||||
_("The Peppol participant ID is not registered on the Peppol network."),
|
||||
)
|
||||
|
||||
def __call__(self, value):
|
||||
if ":" not in value:
|
||||
raise ValidationError(_("A Peppol participant ID always starts with a prefix, followed by a colon (:)."))
|
||||
@@ -146,25 +167,7 @@ class PeppolIdValidator:
|
||||
params={"number": prefix})
|
||||
|
||||
if self.validate_online:
|
||||
base_hostnames = ['participant.sml.prod.tech.peppol.org', 'participant.sml.test.tech.peppol.org']
|
||||
smp_id = base64.b32encode(hashlib.sha256(value.lower().encode()).digest()).decode().rstrip("=")
|
||||
for base_hostname in base_hostnames:
|
||||
smp_domain = f'{smp_id}.iso6523-actorid-upis.{base_hostname}'
|
||||
resolver = dns.resolver.Resolver()
|
||||
try:
|
||||
answers = resolver.resolve(smp_domain, 'NAPTR', lifetime=1.0)
|
||||
if answers:
|
||||
return value
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
# ID not registered, do not set found=True
|
||||
pass
|
||||
except Exception: # noqa
|
||||
# Error likely on our end or infrastructure is down, allow user to proceed
|
||||
return value
|
||||
|
||||
raise ValidationError(
|
||||
_("The Peppol participant ID is not registered on the Peppol network."),
|
||||
)
|
||||
value = self._validate_peppol_id_online(value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -151,12 +151,29 @@ class LoggingMixin:
|
||||
logentry = LogEntry(content_object=self, user=user, action_type=action, event=event,
|
||||
organizer_id=organizer_id, **kwargs)
|
||||
if isinstance(data, dict):
|
||||
sensitivekeys = ['password', 'secret', 'api_key']
|
||||
# sensitivekeys are matched whether contained, not exactly
|
||||
sensitivekeys = [
|
||||
'auth',
|
||||
'key',
|
||||
'token',
|
||||
'password',
|
||||
'Password',
|
||||
'_pass',
|
||||
'salt',
|
||||
'secret',
|
||||
]
|
||||
|
||||
for sensitivekey in sensitivekeys:
|
||||
for k, v in data.items():
|
||||
if (sensitivekey in k) and v:
|
||||
def clean_recursive(d):
|
||||
data = d
|
||||
data_iterator = d.items() if isinstance(d, dict) else enumerate(d)
|
||||
for k, v in data_iterator:
|
||||
if v and any([sensitivekey in str(k) for sensitivekey in sensitivekeys]):
|
||||
data[k] = "********"
|
||||
elif isinstance(v, (list, dict)):
|
||||
data[k] = clean_recursive(v)
|
||||
return data
|
||||
|
||||
data = clean_recursive(data)
|
||||
|
||||
logentry.data = json.dumps(data, cls=CustomJSONEncoder, sort_keys=True)
|
||||
elif data:
|
||||
|
||||
@@ -83,6 +83,8 @@ from .organizer import Organizer, Team
|
||||
if TYPE_CHECKING:
|
||||
from hierarkey.proxy import HierarkeyProxy
|
||||
|
||||
from .organizer import SalesChannel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -336,12 +338,18 @@ class EventMixin:
|
||||
return safe_string(json.dumps(eventdict))
|
||||
|
||||
@classmethod
|
||||
def annotated(cls, qs, channel, voucher=None):
|
||||
def annotated(cls, qs, channel: "str | SalesChannel | list[SalesChannel]", voucher=None):
|
||||
# Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
|
||||
# makes the query SIGNIFICANTLY faster
|
||||
from pretix.base.models import Item, ItemVariation, Quota, SalesChannel
|
||||
|
||||
assert isinstance(channel, (SalesChannel, str))
|
||||
assert isinstance(channel, (SalesChannel, str, list))
|
||||
|
||||
if isinstance(channel, SalesChannel):
|
||||
channel = [channel]
|
||||
|
||||
if isinstance(channel, list):
|
||||
assert all(isinstance(c, SalesChannel) for c in channel)
|
||||
|
||||
sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).filter(
|
||||
Q(variations__isnull=True)
|
||||
@@ -364,8 +372,8 @@ class EventMixin:
|
||||
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
||||
else:
|
||||
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
||||
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
|
||||
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__in=channel))
|
||||
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__in=channel))
|
||||
|
||||
if voucher:
|
||||
if voucher.variation_id:
|
||||
@@ -1661,11 +1669,17 @@ class SubEvent(EventMixin, LoggedModel):
|
||||
return qs_annotated
|
||||
|
||||
@classmethod
|
||||
def annotated(cls, qs, channel, voucher=None):
|
||||
def annotated(cls, qs, channel: "str | SalesChannel | list[SalesChannel]", voucher=None):
|
||||
from .items import SubEventItem, SubEventItemVariation
|
||||
from .organizer import SalesChannel
|
||||
|
||||
assert isinstance(channel, (str, SalesChannel))
|
||||
assert isinstance(channel, (SalesChannel, str, list))
|
||||
|
||||
if isinstance(channel, SalesChannel):
|
||||
channel = [channel]
|
||||
|
||||
if isinstance(channel, list):
|
||||
assert all(isinstance(c, SalesChannel) for c in channel)
|
||||
|
||||
qs = super().annotated(qs, channel, voucher=voucher)
|
||||
qs = qs.annotate(
|
||||
|
||||
@@ -313,7 +313,14 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False, allow_
|
||||
# makes the query SIGNIFICANTLY faster
|
||||
from .organizer import SalesChannel
|
||||
|
||||
assert isinstance(channel, (SalesChannel, str))
|
||||
assert isinstance(channel, (SalesChannel, str, list))
|
||||
|
||||
if isinstance(channel, SalesChannel):
|
||||
channel = [channel]
|
||||
|
||||
if isinstance(channel, list):
|
||||
assert all(isinstance(c, SalesChannel) for c in channel)
|
||||
|
||||
q = (
|
||||
# IMPORTANT: If this is updated, also update the ItemVariation query
|
||||
# in models/event.py: EventMixin.annotated()
|
||||
@@ -325,7 +332,7 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False, allow_
|
||||
if isinstance(channel, str):
|
||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||
else:
|
||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__in=channel))
|
||||
|
||||
if not allow_addons:
|
||||
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
|
||||
|
||||
@@ -330,5 +330,6 @@ def register_default_organizer_permissions(sender, **kwargs):
|
||||
PermissionOption(actions=tuple(), label=pgettext_lazy("permission_level", "No access")),
|
||||
PermissionOption(actions=("read",), label=pgettext_lazy("permission_level", "View")),
|
||||
],
|
||||
help_text=_("View access includes the option to e.g. abort pending emails or retry failed emails."),
|
||||
),
|
||||
]
|
||||
@@ -22,9 +22,9 @@
|
||||
import os
|
||||
import sys
|
||||
from enum import Enum
|
||||
from importlib import metadata
|
||||
from typing import List
|
||||
|
||||
import importlib_metadata as metadata
|
||||
from django.apps import AppConfig, apps
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
@@ -2176,7 +2176,8 @@ class OrderChangeManager:
|
||||
subevent=a.subevent,
|
||||
voucher=None,
|
||||
base_qs=Item.objects.filter(pk=a.item.pk),
|
||||
allow_addons=True
|
||||
allow_addons=True,
|
||||
ignore_hide_sold_out_for_item_ids={a.item.pk}
|
||||
)
|
||||
if (not items) or items[0].current_unavailability_reason:
|
||||
return False
|
||||
|
||||
@@ -126,10 +126,10 @@ def generate_seats(event, subevent, plan, mapping, blocked_guids=None):
|
||||
for s in current_seats.values():
|
||||
if s.has_op:
|
||||
raise SeatProtected(_('You can not change the plan since seat "%s" is not present in the new plan and is '
|
||||
'already sold.', s.name))
|
||||
'already sold.'), s.name)
|
||||
if s.has_v:
|
||||
raise SeatProtected(_('You can not change the plan since seat "%s" is not present in the new plan and is '
|
||||
'already used in a voucher.', s.name))
|
||||
'already used in a voucher.'), s.name)
|
||||
|
||||
Seat.objects.bulk_create(create_seats)
|
||||
CartPosition.objects.filter(addon_to__seat__in=[s.pk for s in current_seats.values()]).delete()
|
||||
|
||||
@@ -1199,11 +1199,14 @@ The ``sender`` keyword argument will contain the organizer.
|
||||
|
||||
customer_signed_in = OrganizerPluginSignal(allow_legacy_plugins=True)
|
||||
"""
|
||||
Arguments: ``customer``
|
||||
Arguments: ``customer``, ``profile``
|
||||
|
||||
This signal is sent out every time a customer signs in. The ``customer`` object
|
||||
is given as the first argument.
|
||||
|
||||
In case of SSO login, the full claims will be passed in the ``profile`` argument,
|
||||
e.g. as ``oidc_claims`` for OIDC. Otherwise, ``profile`` will be ``None``.
|
||||
|
||||
The ``sender`` keyword argument will contain the organizer.
|
||||
"""
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ import json
|
||||
import logging
|
||||
import pathlib
|
||||
import re
|
||||
from importlib import metadata
|
||||
from urllib.parse import urljoin
|
||||
from urllib.request import urlopen
|
||||
|
||||
import importlib_metadata as metadata
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<link rel="stylesheet" type="text/x-scss" href="{% static "pretixcontrol/scss/main.scss" %}" />
|
||||
<link rel="stylesheet" type="text/x-scss" href="{% static "lightbox/css/lightbox.scss" %}" />
|
||||
{% endcompress %}
|
||||
{% vite_importmap %}
|
||||
{% if DEBUG %}
|
||||
<script type="text/javascript" src="{% url 'javascript-catalog' lang=request.LANGUAGE_CODE %}"></script>
|
||||
{% else %}
|
||||
@@ -87,7 +88,6 @@
|
||||
<meta name="theme-color" content="#3b1c4a">
|
||||
<meta name="referrer" content="origin">
|
||||
|
||||
{% vite_importmap %}
|
||||
{% block custom_header %}{% endblock %}
|
||||
</head>
|
||||
<body data-datetimeformat="{{ js_datetime_format }}" data-timeformat="{{ js_time_format }}"
|
||||
|
||||
@@ -225,6 +225,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3" id="editor-toolbox-area">
|
||||
{% if checkin_qr_warning %}
|
||||
<div class="alert alert-warning" id="nocheckin-notice">
|
||||
{% blocktrans trimmed %}
|
||||
This layout does not contain a QR code that can be used to scan tickets at check-in.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="panel panel-default" id="toolbox">
|
||||
<div class="panel-heading">
|
||||
<span id="toolbox-heading">
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
# 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 importlib_metadata as metadata
|
||||
from importlib import metadata as metadata
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
|
||||
@@ -65,6 +65,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
||||
)
|
||||
maxfilesize = settings.FILE_UPLOAD_MAX_SIZE_IMAGE
|
||||
minfilesize = 10
|
||||
checkin_qr_warning = False
|
||||
title = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
@@ -292,6 +293,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
||||
ctx['title'] = self.title
|
||||
ctx['locales'] = [p for p in settings.LANGUAGES if p[0] in self.request.event.settings.locales]
|
||||
ctx['maxfilesize'] = self.maxfilesize
|
||||
ctx['checkin_qr_warning'] = self.checkin_qr_warning
|
||||
return ctx
|
||||
|
||||
|
||||
|
||||
@@ -4,16 +4,16 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-10-28 10:48+0000\n"
|
||||
"PO-Revision-Date: 2026-07-31 18:00+0000\n"
|
||||
"Last-Translator: Nikolai <nikolai@lengefeldt.de>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix/da/"
|
||||
">\n"
|
||||
"PO-Revision-Date: 2026-10-29 17:00+0000\n"
|
||||
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"da/>\n"
|
||||
"Language: da\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 2026.7.1\n"
|
||||
"X-Generator: Weblate 2026.10.1\n"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
@@ -34962,7 +34962,7 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_quota_left.html
|
||||
#, python-format
|
||||
msgid "%(num)s currently available"
|
||||
msgstr "%(num)s pt. tilgængelig"
|
||||
msgstr "%(num)s pt. ledig"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar_week.html
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-10-28 10:48+0000\n"
|
||||
"PO-Revision-Date: 2026-10-26 23:00+0000\n"
|
||||
"Last-Translator: Tim <plicnetwork@gmail.com>\n"
|
||||
"PO-Revision-Date: 2026-10-29 17:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -7656,17 +7656,14 @@ msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr "Mientras tanto, esta tarjeta de regalo se utilizó. Inténtalo de nuevo."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
#, fuzzy
|
||||
#| msgid "Gift card code"
|
||||
msgid "Gift card not found."
|
||||
msgstr "Código de la tarjeta de regalo"
|
||||
msgstr "No se ha encontrado la tarjeta regalo."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
#, fuzzy
|
||||
#| msgid "Only test gift cards can be used in test mode."
|
||||
msgid "Only test gift card can be used in test mode and vice versa."
|
||||
msgstr ""
|
||||
"En el modo de prueba solo se pueden utilizar tarjetas regalo de prueba."
|
||||
"En el modo de prueba solo se pueden utilizar tarjetas regalo de prueba, y "
|
||||
"viceversa."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
@@ -16689,12 +16686,9 @@ msgid "Phone"
|
||||
msgstr "Teléfono"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
#, fuzzy
|
||||
#| msgctxt "sso_oidc"
|
||||
#| msgid "Base URL"
|
||||
msgctxt "sso_oidc"
|
||||
msgid "Base URL / issuer"
|
||||
msgstr "URL de base"
|
||||
msgstr "URL base / emisor"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgctxt "sso_oidc"
|
||||
@@ -16767,21 +16761,16 @@ msgstr ""
|
||||
"endpoint de autorización. Introducir como: {example}"
|
||||
|
||||
#: pretix/control/forms/organizer.py pretix/control/views/organizer.py
|
||||
#, fuzzy
|
||||
#| msgctxt "sso_oidc"
|
||||
#| msgid "Base URL"
|
||||
msgid "Base URL / issuer"
|
||||
msgstr "URL de base"
|
||||
msgstr "URL base / emisor"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgid "Invalidate old client secret and generate a new one"
|
||||
msgstr "Invalidar el antiguo secreto del cliente y generar uno nuevo"
|
||||
|
||||
#: pretix/control/forms/organizer.py pretix/control/views/organizer.py
|
||||
#, fuzzy
|
||||
#| msgid "will be retried"
|
||||
msgid "(will be generated)"
|
||||
msgstr "se volverá a intentar"
|
||||
msgstr "(se generará)"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgid "Organizer short name"
|
||||
@@ -26404,16 +26393,16 @@ msgstr "Cliente SSO:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclient_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
#, fuzzy
|
||||
#| msgid "Create a new SSO client"
|
||||
msgid "Create credentials for a new SSO client"
|
||||
msgstr "Crear un nuevo cliente SSO"
|
||||
msgstr "Crear credenciales para un nuevo cliente de SSO"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclient_edit.html
|
||||
msgid ""
|
||||
"After submitting this form, client credentials for your SSO client will be "
|
||||
"generated."
|
||||
msgstr ""
|
||||
"Una vez enviado este formulario, se generarán las credenciales de cliente "
|
||||
"para tu cliente SSO."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclient_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
@@ -26423,6 +26412,9 @@ msgid ""
|
||||
"href=\"%(url)s\">Using pretix as an SSO provider with external SSO clients</"
|
||||
"a>."
|
||||
msgstr ""
|
||||
"Para obtener más información, consulta nuestra documentación en <a href=\"%"
|
||||
"(url)s\">Uso de Pretix como proveedor de SSO con clientes de SSO externos</a>"
|
||||
"."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
msgid ""
|
||||
@@ -26430,6 +26422,9 @@ msgid ""
|
||||
" \t\"Login with pretix\" in external systems\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" \t«Iniciar sesión con pretix» en sistemas externos\n"
|
||||
" "
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
msgid ""
|
||||
@@ -26454,17 +26449,13 @@ msgid "This SSO provider cannot be deleted since it has already been used."
|
||||
msgstr "Este proveedor de SSO no se puede eliminar porque ya se ha utilizado."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
#, fuzzy
|
||||
#| msgid "Delete SSO provider:"
|
||||
msgid "External SSO provider:"
|
||||
msgstr "Eliminar proveedor de SSO:"
|
||||
msgstr "Proveedor externo de SSO:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoproviders.html
|
||||
#, fuzzy
|
||||
#| msgid "Create a new SSO provider"
|
||||
msgid "Connect to an external SSO provider"
|
||||
msgstr "Agregar un nuevo proveedor SSO"
|
||||
msgstr "Conectarse a un proveedor externo de SSO"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoproviders.html
|
||||
@@ -26473,6 +26464,8 @@ msgid ""
|
||||
"For more information, refer to our documentation on <a href=\"%(url)s\" "
|
||||
"target=\"_blank\">Using pretix as an SSO client</a>."
|
||||
msgstr ""
|
||||
"Para obtener más información, consulta nuestra documentación sobre <a "
|
||||
"href=\"%(url)s\" target=\"_blank\">El uso de pretix como cliente de SSO</a>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
msgctxt "sso"
|
||||
@@ -26485,6 +26478,9 @@ msgid ""
|
||||
" \tConnect to an external login provider\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" \tConectarse a un proveedor de inicio de sesión externo\n"
|
||||
" "
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoproviders.html
|
||||
msgid ""
|
||||
@@ -30025,15 +30021,10 @@ msgid "The provider has been created."
|
||||
msgstr "Se ha creado el proveedor."
|
||||
|
||||
#: pretix/control/views/organizer.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Your changes have been saved. Please note down the following client "
|
||||
#| "secret, it will never be shown again: {secret}"
|
||||
msgid ""
|
||||
"Please note down the following client secret, it will never be shown again."
|
||||
msgstr ""
|
||||
"Se han guardado los cambios. Anote el siguiente secreto de cliente; no se "
|
||||
"volverá a mostrar nunca más: {secret}"
|
||||
"Anota el siguiente secreto de cliente; no volverá a mostrarse nunca más."
|
||||
|
||||
#: pretix/control/views/organizer.py
|
||||
msgid ""
|
||||
@@ -32586,6 +32577,12 @@ msgid ""
|
||||
"one of those get linked to their own separate order page restricted to only "
|
||||
"that product."
|
||||
msgstr ""
|
||||
"Es posible que se envíen varios correos electrónicos a la misma dirección de "
|
||||
"correo si un pedido contiene varios productos para asistentes y se restringe "
|
||||
"el acceso a los productos y, al mismo tiempo, se limita el envío de correos "
|
||||
"únicamente a los asistentes. Esto es intencionado, ya que cada uno de ellos "
|
||||
"se vincula a su propia página de pedido independiente, restringida "
|
||||
"exclusivamente a ese producto."
|
||||
|
||||
#: pretix/plugins/sendmail/forms.py
|
||||
msgid "Filter check-in status"
|
||||
@@ -33498,7 +33495,7 @@ msgstr "MobilePay"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py
|
||||
msgid "Wero"
|
||||
msgstr ""
|
||||
msgstr "Wero"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py
|
||||
msgid "Destination"
|
||||
|
||||
@@ -4,10 +4,10 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-10-28 10:48+0000\n"
|
||||
"PO-Revision-Date: 2026-10-27 17:00+0000\n"
|
||||
"PO-Revision-Date: 2026-10-29 17:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
|
||||
">\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"fr/>\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -7707,16 +7707,14 @@ msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr "Cette carte-cadeau a été utilisée entre-temps. Veuillez réessayer."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
#, fuzzy
|
||||
#| msgid "Gift card code"
|
||||
msgid "Gift card not found."
|
||||
msgstr "Code carte-cadeau"
|
||||
msgstr "Carte cadeau introuvable."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
#, fuzzy
|
||||
#| msgid "Only test gift cards can be used in test mode."
|
||||
msgid "Only test gift card can be used in test mode and vice versa."
|
||||
msgstr "Seules les cartes-cadeaux de test peuvent être utilisées en mode test."
|
||||
msgstr ""
|
||||
"Seule la carte cadeau de test peut être utilisée en mode test, et "
|
||||
"inversement."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
@@ -16850,12 +16848,9 @@ msgid "Phone"
|
||||
msgstr "Téléphone"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
#, fuzzy
|
||||
#| msgctxt "sso_oidc"
|
||||
#| msgid "Base URL"
|
||||
msgctxt "sso_oidc"
|
||||
msgid "Base URL / issuer"
|
||||
msgstr "URL de base"
|
||||
msgstr "URL de base / émetteur"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgctxt "sso_oidc"
|
||||
@@ -16928,21 +16923,16 @@ msgstr ""
|
||||
"Saisissez-les sous la forme suivante : {example}"
|
||||
|
||||
#: pretix/control/forms/organizer.py pretix/control/views/organizer.py
|
||||
#, fuzzy
|
||||
#| msgctxt "sso_oidc"
|
||||
#| msgid "Base URL"
|
||||
msgid "Base URL / issuer"
|
||||
msgstr "URL de base"
|
||||
msgstr "URL de base / émetteur"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgid "Invalidate old client secret and generate a new one"
|
||||
msgstr "Invalider l’ancienne clé secrète client et en générer une nouvelle"
|
||||
|
||||
#: pretix/control/forms/organizer.py pretix/control/views/organizer.py
|
||||
#, fuzzy
|
||||
#| msgid "will be retried"
|
||||
msgid "(will be generated)"
|
||||
msgstr "sera réessayé"
|
||||
msgstr "(sera généré)"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgid "Organizer short name"
|
||||
@@ -26606,16 +26596,16 @@ msgstr "Client SSO :"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclient_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
#, fuzzy
|
||||
#| msgid "Create a new SSO client"
|
||||
msgid "Create credentials for a new SSO client"
|
||||
msgstr "Créer un nouveau client SSO"
|
||||
msgstr "Créer des identifiants pour un nouveau client SSO"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclient_edit.html
|
||||
msgid ""
|
||||
"After submitting this form, client credentials for your SSO client will be "
|
||||
"generated."
|
||||
msgstr ""
|
||||
"Une fois ce formulaire envoyé, les identifiants de votre client SSO seront "
|
||||
"générés."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclient_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
@@ -26625,6 +26615,9 @@ msgid ""
|
||||
"href=\"%(url)s\">Using pretix as an SSO provider with external SSO clients</"
|
||||
"a>."
|
||||
msgstr ""
|
||||
"Pour plus d'informations, consultez notre documentation sur <a href=\"%(url)"
|
||||
"s\">L'utilisation de Pretix en tant que fournisseur SSO avec des clients SSO "
|
||||
"externes</a>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
msgid ""
|
||||
@@ -26632,6 +26625,9 @@ msgid ""
|
||||
" \t\"Login with pretix\" in external systems\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" \t« Se connecter avec pretix » dans les systèmes externes\n"
|
||||
" "
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoclients.html
|
||||
msgid ""
|
||||
@@ -26659,17 +26655,13 @@ msgstr ""
|
||||
"Ce fournisseur SSO ne peut pas être supprimé car il a déjà été utilisé."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
#, fuzzy
|
||||
#| msgid "Delete SSO provider:"
|
||||
msgid "External SSO provider:"
|
||||
msgstr "Supprimer le fournisseur SSO :"
|
||||
msgstr "Fournisseur SSO externe :"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoproviders.html
|
||||
#, fuzzy
|
||||
#| msgid "Create a new SSO provider"
|
||||
msgid "Connect to an external SSO provider"
|
||||
msgstr "Créer un nouveau fournisseur SSO"
|
||||
msgstr "Se connecter à un fournisseur SSO externe"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoproviders.html
|
||||
@@ -26678,6 +26670,8 @@ msgid ""
|
||||
"For more information, refer to our documentation on <a href=\"%(url)s\" "
|
||||
"target=\"_blank\">Using pretix as an SSO client</a>."
|
||||
msgstr ""
|
||||
"Pour plus d'informations, consultez notre documentation sur <a href=\"%(url)"
|
||||
"s\" target=\"_blank\">L'utilisation de pretix en tant que client SSO</a>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoprovider_edit.html
|
||||
msgctxt "sso"
|
||||
@@ -26690,6 +26684,9 @@ msgid ""
|
||||
" \tConnect to an external login provider\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" \tSe connecter à un fournisseur d'authentification externe\n"
|
||||
" "
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/ssoproviders.html
|
||||
msgid ""
|
||||
@@ -30269,15 +30266,10 @@ msgid "The provider has been created."
|
||||
msgstr "Le fournisseur a été créé."
|
||||
|
||||
#: pretix/control/views/organizer.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Your changes have been saved. Please note down the following client "
|
||||
#| "secret, it will never be shown again: {secret}"
|
||||
msgid ""
|
||||
"Please note down the following client secret, it will never be shown again."
|
||||
msgstr ""
|
||||
"Vos modifications ont été enregistrées. Veuillez noter la clé secrète client "
|
||||
"suivante, elle ne sera plus jamais affichée : {secret}"
|
||||
"Veuillez noter le secret client suivant ; il ne s'affichera plus jamais."
|
||||
|
||||
#: pretix/control/views/organizer.py
|
||||
msgid ""
|
||||
@@ -32862,6 +32854,12 @@ msgid ""
|
||||
"one of those get linked to their own separate order page restricted to only "
|
||||
"that product."
|
||||
msgstr ""
|
||||
"Il se peut que plusieurs e-mails soient envoyés à la même adresse e-mail si "
|
||||
"une commande comprend plusieurs produits destinés à des participants, "
|
||||
"lorsque vous limitez l'accès aux produits tout en restreignant les e-mails "
|
||||
"aux seuls participants. Ce comportement est normal, car chacun de ces "
|
||||
"produits est associé à sa propre page de commande, dont l'accès est limité à "
|
||||
"ce produit uniquement."
|
||||
|
||||
#: pretix/plugins/sendmail/forms.py
|
||||
msgid "Filter check-in status"
|
||||
@@ -33777,7 +33775,7 @@ msgstr "MobilePay"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py
|
||||
msgid "Wero"
|
||||
msgstr ""
|
||||
msgstr "Wero"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py
|
||||
msgid "Destination"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-10-28 10:48+0000\n"
|
||||
"PO-Revision-Date: 2026-04-21 11:05+0000\n"
|
||||
"Last-Translator: Sandra Rial Pérez <sandrarial@gestiontickets.online>\n"
|
||||
"PO-Revision-Date: 2026-11-02 11:32+0000\n"
|
||||
"Last-Translator: Isaac Raño <isaac@ovixia.com>\n"
|
||||
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"gl/>\n"
|
||||
"Language: gl\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.17\n"
|
||||
"X-Generator: Weblate 2026.10.1\n"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
@@ -93,7 +93,7 @@ msgstr "Hebreo"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "Hungarian"
|
||||
msgstr ""
|
||||
msgstr "Húngaro"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "Indonesian"
|
||||
@@ -153,7 +153,7 @@ msgstr "Español (América Latina)"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "Thai"
|
||||
msgstr ""
|
||||
msgstr "Tailandés"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "Turkish"
|
||||
@@ -409,7 +409,7 @@ msgstr ""
|
||||
#: pretix/api/serializers/organizer.py pretix/control/views/organizer.py
|
||||
#, python-format
|
||||
msgid "You've been invited to join %(organizer)s"
|
||||
msgstr ""
|
||||
msgstr "Convidáronte a unirte a %(organizer)s"
|
||||
|
||||
#: pretix/api/serializers/organizer.py pretix/control/views/organizer.py
|
||||
msgid "This user already has been invited for this team."
|
||||
@@ -429,9 +429,8 @@ msgid "Medium connected to other event"
|
||||
msgstr "O medio conectou a outro acontecemento"
|
||||
|
||||
#: pretix/api/views/checkin.py
|
||||
#, fuzzy
|
||||
msgid "You cannot exchange a medium for a medium."
|
||||
msgstr "No puede cancelar este pedido."
|
||||
msgstr "Non se pode trocar un medio por outro."
|
||||
|
||||
#: pretix/api/views/checkin.py
|
||||
#, fuzzy
|
||||
|
||||
@@ -7,16 +7,16 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-10-28 10:48+0000\n"
|
||||
"PO-Revision-Date: 2026-10-19 02:00+0000\n"
|
||||
"PO-Revision-Date: 2026-11-03 08:12+0000\n"
|
||||
"Last-Translator: Christiaan de Die le Clercq <contact@techwolf12.nl>\n"
|
||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/"
|
||||
">\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 2026.10.1\n"
|
||||
"X-Generator: Weblate 2026.11\n"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
@@ -8379,12 +8379,12 @@ msgstr "Niet ingesteld"
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
msgid "A relative date cannot be expressed as \"before\" for \"{}\""
|
||||
msgstr ""
|
||||
msgstr "Een relatieve datum kan niet worden uitgedrukt als \"voor\" voor \"{}\""
|
||||
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
msgid "A relative date cannot be expressed as \"after\" for \"{}\""
|
||||
msgstr ""
|
||||
msgstr "Een relatieve datum kan niet worden uitgedrukt als \"na\" voor \"{}\""
|
||||
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
@@ -8415,7 +8415,7 @@ msgstr "Evenement geannuleerd"
|
||||
|
||||
#: pretix/base/services/cancelevent.py
|
||||
msgid "Confirm event cancellation and bulk refund"
|
||||
msgstr ""
|
||||
msgstr "Evenementannulering en bulkterugbetaling bevestigen"
|
||||
|
||||
#: pretix/base/services/cart.py pretix/base/services/modelimport.py
|
||||
#: pretix/base/services/orders.py
|
||||
@@ -9355,6 +9355,7 @@ msgstr "Een voucher kan niet worden aangemaakt zonder code."
|
||||
msgid ""
|
||||
"Voucher codes must be unique. Code \"{code}\" already exists in this import."
|
||||
msgstr ""
|
||||
"Vouchercodes moeten uniek zijn. Code \"{code}\" bestaat al in deze import."
|
||||
|
||||
#: pretix/base/services/modelimport.py
|
||||
#, python-brace-format
|
||||
@@ -9363,13 +9364,18 @@ msgid ""
|
||||
msgid_plural ""
|
||||
"Voucher codes must be unique. Import contains existing voucher codes {code}."
|
||||
msgstr[0] ""
|
||||
"Vouchercodes moeten uniek zijn. Import bevat al bestaande vouchercode {code}."
|
||||
msgstr[1] ""
|
||||
"Vouchercodes moeten uniek zijn. Import bevat al bestaande vouchercodes {code}"
|
||||
"."
|
||||
|
||||
#: pretix/base/services/modelimport.py
|
||||
msgid ""
|
||||
"Vouchers could not be imported, probably due to a voucher code already being "
|
||||
"in use."
|
||||
msgstr ""
|
||||
"Vouchers konden niet worden geïmporteerd, waarschijnlijk omdat een "
|
||||
"vouchercode al in gebruik is."
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
msgid ""
|
||||
@@ -10431,7 +10437,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "No dates match your criteria."
|
||||
msgstr ""
|
||||
msgstr "Geen data voldoen aan je zoekcriteria."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgctxt "subevents"
|
||||
@@ -10632,6 +10638,10 @@ msgid ""
|
||||
"their order without selecting a payment method. This is useful whenever "
|
||||
"orders are not created by the same person who is making the payment."
|
||||
msgstr ""
|
||||
"Als uitgestelde betaling is toegestaan op een verkoopkanaal, kunnen klanten "
|
||||
"hun bestelling afronden zonder een betaalmethode te kiezen. Dit is handig "
|
||||
"wanneer bestellingen niet worden geplaatst door dezelfde persoon als degene "
|
||||
"die de betaling uitvoert."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "Show start date"
|
||||
@@ -11603,6 +11613,10 @@ msgid ""
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
"email address that will be shared with all emails you send."
|
||||
msgstr ""
|
||||
"Als je dit instelt, verwijst de contactlink in de voettekst hiernaartoe in "
|
||||
"plaats van naar het bovenstaande e-mailadres. Let op dat je nog steeds een "
|
||||
"contact-e-mailadres moet toevoegen dat wordt meegestuurd met alle e-mails "
|
||||
"die je verzendt."
|
||||
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid "Imprint URL"
|
||||
@@ -13494,6 +13508,8 @@ msgid ""
|
||||
"Don't share this code with anyone. The %(instance)s team will never ask you "
|
||||
"for it."
|
||||
msgstr ""
|
||||
"Deel deze code met niemand. Het %(instance)s-team zal je hier nooit om "
|
||||
"vragen."
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/cancel_confirm.txt
|
||||
#: pretix/base/templates/pretixbase/email/export_failed.txt
|
||||
@@ -13502,6 +13518,8 @@ msgid ""
|
||||
"Thanks, \n"
|
||||
"The %(instance)s Team"
|
||||
msgstr ""
|
||||
"Bedankt, \n"
|
||||
"Het %(instance)s-team"
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/email_footer.html
|
||||
#, python-format
|
||||
@@ -13698,11 +13716,14 @@ msgstr "Ga verder in een nieuw tabblad"
|
||||
#: pretix/base/templates/pretixbase/framebreak.html
|
||||
msgid "For security reasons, the following step is only possible in a new tab."
|
||||
msgstr ""
|
||||
"Om veiligheidsredenen is de volgende stap alleen mogelijk in een nieuw "
|
||||
"tabblad."
|
||||
|
||||
#: pretix/base/templates/pretixbase/framebreak.html
|
||||
msgid ""
|
||||
"If the new tab did not open automatically, please click the following button:"
|
||||
msgstr ""
|
||||
"Als het nieuwe tabblad niet automatisch opent, klik dan op de volgende knop:"
|
||||
|
||||
#: pretix/base/templates/pretixbase/framebreak.html
|
||||
#: pretix/presale/templates/pretixpresale/event/cookies.html
|
||||
@@ -37134,6 +37155,10 @@ msgid ""
|
||||
"before retrying can help. As a last step, try using a different browser or "
|
||||
"another device (for example, a desktop or laptop computer)."
|
||||
msgstr ""
|
||||
"Als het probleem zich blijft voordoen, kan het helpen om alle "
|
||||
"browservensters te sluiten en cookies te verwijderen voordat je het opnieuw "
|
||||
"probeert. Als laatste stap kun je proberen een andere browser of een ander "
|
||||
"apparaat (bijvoorbeeld een desktop of laptop) te gebruiken."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Your membership"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-10-28 10:48+0000\n"
|
||||
"PO-Revision-Date: 2026-09-02 08:35+0000\n"
|
||||
"Last-Translator: Renne Rocha <renne@rocha.dev.br>\n"
|
||||
"PO-Revision-Date: 2026-10-30 03:00+0000\n"
|
||||
"Last-Translator: vihumelo <victordimelo@gmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
|
||||
"pretix/pretix/pt_BR/>\n"
|
||||
"Language: pt_BR\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 2026.8.1\n"
|
||||
"X-Generator: Weblate 2026.10.1\n"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
@@ -411,7 +411,7 @@ msgstr ""
|
||||
#: pretix/api/serializers/organizer.py pretix/control/views/organizer.py
|
||||
#, python-format
|
||||
msgid "You've been invited to join %(organizer)s"
|
||||
msgstr ""
|
||||
msgstr "Você recebeu um convite para integrar %(organizer)s"
|
||||
|
||||
#: pretix/api/serializers/organizer.py pretix/control/views/organizer.py
|
||||
msgid "This user already has been invited for this team."
|
||||
@@ -607,6 +607,9 @@ msgid ""
|
||||
"This includes related events like creation, deletion, opening or closing of "
|
||||
"quotas. No webhook is sent for changes to the resulting availability."
|
||||
msgstr ""
|
||||
"Isso inclui eventos relacionados, como a criação, exclusão, abertura ou "
|
||||
"fechamento de cotas. Nenhum webhook é enviado em decorrência de alterações "
|
||||
"na disponibilidade."
|
||||
|
||||
#: pretix/api/webhooks.py
|
||||
msgid "Shop taken live"
|
||||
@@ -1678,7 +1681,7 @@ msgstr "Endereço"
|
||||
#: pretix/base/settings.py pretix/control/forms/filter.py
|
||||
#: pretix/plugins/checkinlists/exporters.py pretix/plugins/reports/exporters.py
|
||||
msgid "ZIP code"
|
||||
msgstr "Código Postal"
|
||||
msgstr "CEP"
|
||||
|
||||
#: pretix/base/exporters/invoices.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/modelimport_orders.py
|
||||
@@ -3622,6 +3625,9 @@ msgid ""
|
||||
"The Peppol participant ID prefix %(number)s is not known to our system. "
|
||||
"Please reach out to us if you are sure this ID is correct."
|
||||
msgstr ""
|
||||
"Nosso sistema não reconhece o prefixo %(number)s do identificador de "
|
||||
"participante da Peppol. Se você tem certeza de que esse identificador está "
|
||||
"correto, entre em contato conosco."
|
||||
|
||||
#: pretix/base/invoicing/peppol.py
|
||||
#, python-format
|
||||
@@ -5600,6 +5606,9 @@ msgid ""
|
||||
"prior to their usage. Therefore, the selected media policy does not make "
|
||||
"sense for this media type."
|
||||
msgstr ""
|
||||
"O tipo de mídia selecionado exige que todas as mídias sejam cadastradas no "
|
||||
"sistema antes de serem utilizadas. Portanto, a política de mídia selecionada "
|
||||
"não é adequada para esse tipo de mídia."
|
||||
|
||||
#: pretix/base/models/items.py
|
||||
msgid ""
|
||||
@@ -5821,7 +5830,7 @@ msgstr "Código do país (ISO 3166-1 alfa-2)"
|
||||
|
||||
#: pretix/base/models/items.py
|
||||
msgid "Asked on"
|
||||
msgstr ""
|
||||
msgstr "Pergunta feita em"
|
||||
|
||||
#: pretix/base/models/items.py pretix/base/models/organizer.py
|
||||
msgid ""
|
||||
@@ -6171,12 +6180,12 @@ msgstr "retornou"
|
||||
#: pretix/base/models/media.py
|
||||
msgctxt "reusable_medium"
|
||||
msgid "Claim token"
|
||||
msgstr ""
|
||||
msgstr "Token de vinculação"
|
||||
|
||||
#: pretix/base/models/media.py
|
||||
msgctxt "reusable_medium"
|
||||
msgid "Label"
|
||||
msgstr ""
|
||||
msgstr "Rótulo"
|
||||
|
||||
#: pretix/base/models/media.py
|
||||
#, fuzzy
|
||||
@@ -6190,6 +6199,9 @@ msgid ""
|
||||
"validity. If multiple tickets are valid at once, this will lead to failed "
|
||||
"check-ins."
|
||||
msgstr ""
|
||||
"Se você vincular mais de um ingresso, certifique-se de que os períodos de "
|
||||
"validade não se sobreponham. Se vários ingressos estiverem válidos ao mesmo "
|
||||
"tempo, poderão ocorrer falhas no check-in."
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
@@ -8119,6 +8131,8 @@ msgstr "Apenas API"
|
||||
msgid ""
|
||||
"Menu item will only show up if the user has permission for general settings."
|
||||
msgstr ""
|
||||
"Esta opção só será exibida no menu se o usuário tiver permissão para acessar "
|
||||
"as configurações gerais."
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
msgctxt "permission_level"
|
||||
@@ -8136,6 +8150,8 @@ msgid ""
|
||||
"This includes access to all settings not listed explicitly below, including "
|
||||
"plugin settings."
|
||||
msgstr ""
|
||||
"Isso inclui o acesso a todas as configurações que não estão explicitamente "
|
||||
"listadas abaixo, incluindo as configurações dos plugins."
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
#: pretix/control/templates/pretixcontrol/event/payment.html
|
||||
@@ -8165,7 +8181,7 @@ msgstr "Produtos, cotas e perguntas"
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
msgid "Also includes related objects like categories or discounts."
|
||||
msgstr ""
|
||||
msgstr "Também inclui elementos relacionados, como categorias ou descontos."
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
msgctxt "permission_level"
|
||||
@@ -8219,12 +8235,14 @@ msgstr "Acessar eventos existentes"
|
||||
#: pretix/base/permissions.py
|
||||
msgctxt "permission_level"
|
||||
msgid "Access existing and create new events"
|
||||
msgstr ""
|
||||
msgstr "Acessar eventos existentes e criar novos eventos"
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
msgid ""
|
||||
"The level of access to events is determined in detail by the settings below."
|
||||
msgstr ""
|
||||
"O nível de acesso aos eventos é definido detalhadamente pelas configurações "
|
||||
"abaixo."
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/event/invoicing.html
|
||||
@@ -8241,12 +8259,17 @@ msgid ""
|
||||
"This includes access to all organizer-level functionality not listed "
|
||||
"explicitly below, including plugin settings."
|
||||
msgstr ""
|
||||
"Isso inclui o acesso a todas as funcionalidades disponíveis no nível do "
|
||||
"organizador que não estejam explicitamente listadas abaixo, incluindo as "
|
||||
"configurações dos plugins."
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
msgid ""
|
||||
"Includes the ability to give someone (including oneself) additional "
|
||||
"permissions."
|
||||
msgstr ""
|
||||
"Inclui a possibilidade de conceder permissões adicionais a alguém (inclusive "
|
||||
"a si mesmo)."
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
@@ -8257,6 +8280,8 @@ msgid ""
|
||||
"Includes the ability to give access to events and data oneself does not have "
|
||||
"access to."
|
||||
msgstr ""
|
||||
"Inclui a possibilidade de conceder acesso a eventos e dados aos quais você "
|
||||
"mesmo não tem acesso."
|
||||
|
||||
#: pretix/base/permissions.py
|
||||
#, fuzzy
|
||||
@@ -8349,22 +8374,22 @@ msgstr "Não definido"
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
msgid "A relative date cannot be expressed as \"before\" for \"{}\""
|
||||
msgstr ""
|
||||
msgstr "Uma data relativa não pode ser expressa como \"antes de\" para \"{}\""
|
||||
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
msgid "A relative date cannot be expressed as \"after\" for \"{}\""
|
||||
msgstr ""
|
||||
msgstr "Uma data relativa não pode ser expressa como \"depois de\" para \"{}\""
|
||||
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
msgid "A relative time cannot be expressed as \"before\" for \"{}\""
|
||||
msgstr ""
|
||||
msgstr "Um tempo relativo não pode ser expresso como \"antes de\" para \"{}\""
|
||||
|
||||
#: pretix/base/reldate.py
|
||||
#, python-brace-format
|
||||
msgid "A relative time cannot be expressed as \"after\" for \"{}\""
|
||||
msgstr ""
|
||||
msgstr "Um tempo relativo não pode ser expresso como \"depois de\" para \"{}\""
|
||||
|
||||
#: pretix/base/secrets.py
|
||||
msgid "Random (default, works with all pretix apps)"
|
||||
@@ -8385,7 +8410,7 @@ msgstr "Evento cancelado"
|
||||
|
||||
#: pretix/base/services/cancelevent.py
|
||||
msgid "Confirm event cancellation and bulk refund"
|
||||
msgstr ""
|
||||
msgstr "Confirmar o cancelamento do evento e o reembolso em massa"
|
||||
|
||||
#: pretix/base/services/cart.py pretix/base/services/modelimport.py
|
||||
#: pretix/base/services/orders.py
|
||||
@@ -8933,13 +8958,15 @@ msgstr "Você precisa responder a perguntas para concluir este check-in."
|
||||
|
||||
#: pretix/base/services/checkin.py
|
||||
msgid "Ticket needs to be exchanged to a suitable medium."
|
||||
msgstr ""
|
||||
msgstr "O ingresso precisa ser trocado por um meio adequado."
|
||||
|
||||
#: pretix/base/services/checkin.py
|
||||
msgid ""
|
||||
"This ticket has already been exchanged for a reusable medium that now needs "
|
||||
"to be used instead."
|
||||
msgstr ""
|
||||
"Este ingresso já foi trocado por uma mídia reutilizável, que agora deve ser "
|
||||
"utilizado em seu lugar."
|
||||
|
||||
#: pretix/base/services/checkin.py
|
||||
msgid "This ticket has already been redeemed."
|
||||
@@ -9105,62 +9132,44 @@ msgid "You are receiving this email because you placed an order for {event}."
|
||||
msgstr "Você está recebendo este email porque fez um pedido para {event}."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "Invalid input type."
|
||||
msgid "Invalid medium type."
|
||||
msgstr "Tipo de entrada inválido."
|
||||
msgstr "Tipo de mídia inválido."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "The selected media type is not enabled in your organizer settings."
|
||||
msgid "Medium type is not enabled for organizer."
|
||||
msgstr ""
|
||||
"O tipo de mídia selecionado não está habilitado nas configurações do "
|
||||
"organizador."
|
||||
msgstr "O tipo de mídia não está habilitado para o organizador."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
msgid "Incorrect medium type for product."
|
||||
msgstr ""
|
||||
msgstr "Tipo de mídia incorreto para o produto."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "This ticket has already been redeemed."
|
||||
msgid "Ticket is already exchanged for reusable medium."
|
||||
msgstr "Este ingresso já foi resgatado."
|
||||
msgstr "Este ingresso já foi trocado por uma mídia reutilizável."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "Reusable Medium ID"
|
||||
msgid "Reusable medium not found."
|
||||
msgstr "ID de mídia reutilizável"
|
||||
msgstr "Mídia reutilizável não encontrada."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "The reusable medium has been created."
|
||||
msgid "Reusable medium is inactive or expired."
|
||||
msgstr "A mídia reutilizável foi criada."
|
||||
msgstr "A mídia reutilizável está inativa ou expirada."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "The reusable medium has been created."
|
||||
msgid "Reusable medium not found and could not be created."
|
||||
msgstr "A mídia reutilizável foi criada."
|
||||
msgstr "A mídia reutilizável não foi encontrada e não pôde ser criada."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "Reusable media type"
|
||||
msgid "Reusable medium already exists."
|
||||
msgstr "Tipo de mídia reutilizável"
|
||||
msgstr "A mídia reutilizável já existe."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
#, fuzzy
|
||||
#| msgid "The reusable medium has been created."
|
||||
msgid "Reusable medium could not be created."
|
||||
msgstr "A mídia reutilizável foi criada."
|
||||
msgstr "Não foi possível criar a mídia reutilizável."
|
||||
|
||||
#: pretix/base/services/media.py
|
||||
msgid "Product does not support medium exchange."
|
||||
msgstr ""
|
||||
msgstr "O produto não permite a troca por mídia."
|
||||
|
||||
#: pretix/base/services/memberships.py
|
||||
#, python-brace-format
|
||||
@@ -9325,6 +9334,8 @@ msgstr "Um cupom não pode ser criado sem um código."
|
||||
msgid ""
|
||||
"Voucher codes must be unique. Code \"{code}\" already exists in this import."
|
||||
msgstr ""
|
||||
"Os códigos dos cupons devem ser únicos. O código \"{code}\" já existe nesta "
|
||||
"importação."
|
||||
|
||||
#: pretix/base/services/modelimport.py
|
||||
#, python-brace-format
|
||||
@@ -9333,13 +9344,19 @@ msgid ""
|
||||
msgid_plural ""
|
||||
"Voucher codes must be unique. Import contains existing voucher codes {code}."
|
||||
msgstr[0] ""
|
||||
"Os códigos dos cupons devem ser únicos. A importação contém um código de "
|
||||
"cupom já existente: {code}."
|
||||
msgstr[1] ""
|
||||
"Os códigos dos cupons devem ser únicos. A importação contém códigos de "
|
||||
"cupons já existentes: {code}."
|
||||
|
||||
#: pretix/base/services/modelimport.py
|
||||
msgid ""
|
||||
"Vouchers could not be imported, probably due to a voucher code already being "
|
||||
"in use."
|
||||
msgstr ""
|
||||
"Não foi possível importar os cupons, provavelmente porque um dos códigos já "
|
||||
"está em uso."
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
msgid ""
|
||||
@@ -9917,7 +9934,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "Enforce the usage of issued reusable media for check-in"
|
||||
msgstr ""
|
||||
msgstr "Exigir o uso de mídias reutilizáveis emitidas para realizar o check-in"
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid ""
|
||||
@@ -9925,6 +9942,10 @@ msgid ""
|
||||
"medium has been created and linked to a ticket. Keeping this option turned "
|
||||
"off will treat the reusable medium and ticket as equals."
|
||||
msgstr ""
|
||||
"Se esta opção estiver ativada, o código de barras do ingresso não será mais "
|
||||
"aceito caso uma mídia reutilizável tenha sido criada e vinculada a ele. Se a "
|
||||
"opção permanecer desativada, a mídia reutilizável e o ingresso serão "
|
||||
"considerados equivalentes."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "Length of barcodes"
|
||||
@@ -10392,12 +10413,12 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "No dates match your criteria."
|
||||
msgstr ""
|
||||
msgstr "Nenhuma data corresponde aos seus critérios."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgctxt "subevents"
|
||||
msgid "Text for empty date results"
|
||||
msgstr ""
|
||||
msgstr "Texto exibido quando a data não retorna resultados"
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgctxt "subevents"
|
||||
@@ -10408,6 +10429,11 @@ msgid ""
|
||||
"touch with you to arrange further dates. We do not recommend more than one "
|
||||
"or two sentences."
|
||||
msgstr ""
|
||||
"Este texto será exibido quando o calendário ou a lista de datas estiver "
|
||||
"vazio, por exemplo, quando não houver datas disponíveis em determinado mês "
|
||||
"ou quando um filtro selecionado pelo usuário não retornar resultados. Você "
|
||||
"pode usar esse espaço para informar como entrar em contato com você para "
|
||||
"combinar novas datas. Recomendamos usar apenas uma ou duas frases."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "Guidance text"
|
||||
@@ -10593,6 +10619,9 @@ msgid ""
|
||||
"their order without selecting a payment method. This is useful whenever "
|
||||
"orders are not created by the same person who is making the payment."
|
||||
msgstr ""
|
||||
"Se o pagamento posterior for permitido em um canal de vendas, os clientes "
|
||||
"poderão concluir seus pedidos sem selecionar uma forma de pagamento. Isso é "
|
||||
"útil quando a pessoa que faz o pedido não é a mesma que realiza o pagamento."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "Show start date"
|
||||
@@ -11561,6 +11590,10 @@ msgid ""
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
"email address that will be shared with all emails you send."
|
||||
msgstr ""
|
||||
"Se você configurar esta opção, o link de contato no rodapé direcionará para "
|
||||
"o endereço informado aqui, em vez de utilizar o endereço de e-mail acima. "
|
||||
"Observe que ainda será necessário informar um endereço de e-mail de contato, "
|
||||
"que será incluído em todos os e-mails enviados."
|
||||
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid "Imprint URL"
|
||||
@@ -13156,7 +13189,7 @@ msgstr ""
|
||||
#: pretix/base/settings.py
|
||||
#, python-brace-format
|
||||
msgid "VAT-ID is not supported for \"{}\"."
|
||||
msgstr ""
|
||||
msgstr "O VAT-ID não é compatível para \"{}\"."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
msgid "The last payment date cannot be before the end of presale."
|
||||
@@ -13451,6 +13484,8 @@ msgid ""
|
||||
"Don't share this code with anyone. The %(instance)s team will never ask you "
|
||||
"for it."
|
||||
msgstr ""
|
||||
"Não compartilhe este código com ninguém. A equipe do %(instance)s nunca "
|
||||
"solicitará esse código."
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/cancel_confirm.txt
|
||||
#: pretix/base/templates/pretixbase/email/export_failed.txt
|
||||
@@ -13459,6 +13494,8 @@ msgid ""
|
||||
"Thanks, \n"
|
||||
"The %(instance)s Team"
|
||||
msgstr ""
|
||||
"Obrigado,\n"
|
||||
"Time %(instance)s"
|
||||
|
||||
#: pretix/base/templates/pretixbase/email/email_footer.html
|
||||
#, python-format
|
||||
@@ -14021,6 +14058,8 @@ msgid ""
|
||||
"You entered an URL, which is not allowed. Please remove %(match)s from your "
|
||||
"input."
|
||||
msgstr ""
|
||||
"Você inseriu uma URL, o que não é permitido. Remova %(match)s do texto "
|
||||
"informado."
|
||||
|
||||
#: pretix/base/views/errors.py
|
||||
msgid ""
|
||||
@@ -14281,6 +14320,8 @@ msgid ""
|
||||
"You cannot choose a team that would give you more access than you have on "
|
||||
"the event you are copying."
|
||||
msgstr ""
|
||||
"Você não pode escolher um time que lhe conceda um nível de acesso superior "
|
||||
"ao que você possui no evento que está copiando."
|
||||
|
||||
#: pretix/control/forms/event.py
|
||||
msgid "Copy configuration from"
|
||||
@@ -14295,6 +14336,8 @@ msgid ""
|
||||
"You cannot choose an event on which you have less access than the team you "
|
||||
"selected in the previous step."
|
||||
msgstr ""
|
||||
"Você não pode escolher um evento no qual tenha um nível de acesso inferior "
|
||||
"ao do time selecionado na etapa anterior."
|
||||
|
||||
#: pretix/control/forms/event.py pretix/control/forms/item.py
|
||||
#: pretix/control/forms/subevents.py
|
||||
@@ -14397,7 +14440,7 @@ msgstr "Data de pagamento"
|
||||
|
||||
#: pretix/control/forms/event.py
|
||||
msgid "same as above"
|
||||
msgstr ""
|
||||
msgstr "o mesmo que acima"
|
||||
|
||||
#: pretix/control/forms/event.py
|
||||
#, fuzzy
|
||||
@@ -14479,6 +14522,13 @@ msgid ""
|
||||
"configured whenever possible. Gross prices may still change if they are "
|
||||
"impossible to derive from a rounded net price."
|
||||
msgstr ""
|
||||
"Recomendado para a emissão de faturas eletrônicas quando você vende "
|
||||
"principalmente para consumidores finais. Os preços brutos ou líquidos de "
|
||||
"alguns produtos podem ser ajustados automaticamente para garantir o "
|
||||
"arredondamento correto do total do pedido. O sistema procura manter os "
|
||||
"preços brutos conforme configurados sempre que possível. No entanto, esses "
|
||||
"preços ainda podem sofrer alterações quando não for possível calculá-los a "
|
||||
"partir de um preço líquido arredondado."
|
||||
|
||||
#: pretix/control/forms/event.py
|
||||
msgid "Generate invoices for Sales channels"
|
||||
@@ -16648,7 +16698,7 @@ msgstr "Você pode definir apenas um domínio de organizador."
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgid "Provided by a plugin"
|
||||
msgstr ""
|
||||
msgstr "Fornecido por um plugin"
|
||||
|
||||
#: pretix/control/forms/organizer.py
|
||||
msgid ""
|
||||
@@ -16906,7 +16956,7 @@ msgstr "terceiro"
|
||||
#: pretix/control/forms/rrule.py
|
||||
msgctxt "rrule"
|
||||
msgid "fourth"
|
||||
msgstr ""
|
||||
msgstr "quarto"
|
||||
|
||||
#: pretix/control/forms/rrule.py
|
||||
msgctxt "rrule"
|
||||
@@ -16925,7 +16975,7 @@ msgstr "Dia do fim de semana"
|
||||
#: pretix/control/forms/subevents.py
|
||||
msgctxt "subevent"
|
||||
msgid "Skip dates that overlap with any existing date"
|
||||
msgstr ""
|
||||
msgstr "Ignorar datas que se sobreponham a qualquer data existente"
|
||||
|
||||
#: pretix/control/forms/subevents.py
|
||||
msgctxt "subevent"
|
||||
@@ -16935,6 +16985,10 @@ msgid ""
|
||||
"This respects even inactive dates and works best if all dates have both a "
|
||||
"start and end time."
|
||||
msgstr ""
|
||||
"Isso pode ser útil se todas as datas ocorrerem no mesmo local e você quiser "
|
||||
"evitar a criação de datas recorrentes que entrem em conflito com eventos "
|
||||
"especiais já existentes. Essa opção também considera as datas inativas e "
|
||||
"funciona melhor quando todas as datas têm horários de início e término."
|
||||
|
||||
#: pretix/control/forms/subevents.py
|
||||
msgid "Keep the current values"
|
||||
@@ -16984,6 +17038,9 @@ msgid ""
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
"Você não pode reduzir o número máximo de resgates para %(max_usages)s, pois "
|
||||
"pelo menos um dos cupons selecionados já foi resgatato %(max_redeemed)s "
|
||||
"vezes."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
@@ -17017,6 +17074,8 @@ msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
"Não é possível alterar em massa o número máximo de utilizações se algum dos "
|
||||
"cupons selecionados estiver vinculado a um assento."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
@@ -17024,18 +17083,24 @@ msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
"Não é possível alterar a data em massa se algum dos cupons selecionados "
|
||||
"estiver vinculado a um assento."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
"Não é possível alterar o produto para uma cota se algum dos cupons "
|
||||
"selecionados estiver vinculado a um assento."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
"Esta alteração não pode ser concluída porque nem todos os assentos "
|
||||
"vinculados aos cupons ainda estão disponíveis"
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
@@ -18198,6 +18263,8 @@ msgid ""
|
||||
"The ticket #{positionid} was exchanged for reusable medium "
|
||||
"{medium_identifier}."
|
||||
msgstr ""
|
||||
"O ingresso #{positionid} foi trocado pela mídia reutilizável "
|
||||
"{medium_identifier}."
|
||||
|
||||
#: pretix/control/logdisplay.py
|
||||
msgid "The medium has been connected to a new gift card."
|
||||
@@ -18255,6 +18322,8 @@ msgstr "Um código de emergência de dois fatores foi gerado."
|
||||
#: pretix/control/logdisplay.py
|
||||
msgid "Drift and throttle values for two-factor devices have been reset."
|
||||
msgstr ""
|
||||
"Os dados de sincronização e de controle de tentativas dos dispositivos de "
|
||||
"autenticação de dois fatores foram redefinidos."
|
||||
|
||||
#: pretix/control/logdisplay.py
|
||||
#, python-brace-format
|
||||
@@ -20067,6 +20136,8 @@ msgid ""
|
||||
"This ticket needs to be exchanged into a <strong>%(media_type)s</strong> "
|
||||
"reusable medium. <strong>%(media_policy)s</strong>."
|
||||
msgstr ""
|
||||
"Este ingresso precisa ser trocado por uma mídia reutilizável do tipo <strong>"
|
||||
"%(media_type)s</strong>. <strong>%(media_policy)s</strong>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/checkin/simulator.html
|
||||
msgid "Special attention required"
|
||||
@@ -20322,6 +20393,18 @@ msgid ""
|
||||
"Thanks, \n"
|
||||
"The %(instance)s Team\n"
|
||||
msgstr ""
|
||||
"Olá,\n"
|
||||
"\n"
|
||||
"Recebemos uma solicitação para redefinir a senha da sua conta %(instance)s. "
|
||||
"Para definir uma nova senha, acesse o link abaixo:\n"
|
||||
"\n"
|
||||
"%(url)s\n"
|
||||
"\n"
|
||||
"Se você não fez essa solicitação, pode ignorar este e-mail com segurança — "
|
||||
"sua senha não será alterada.\n"
|
||||
"\n"
|
||||
"Obrigado,\n"
|
||||
"Equipe %(instance)s\n"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/invitation.txt
|
||||
#, fuzzy, python-format
|
||||
@@ -20385,14 +20468,17 @@ msgid ""
|
||||
"\n"
|
||||
"We noticed a new sign-in to your %(instance)s account:\n"
|
||||
msgstr ""
|
||||
"Olá,\n"
|
||||
"\n"
|
||||
"Identificamos um novo acesso à sua conta %(instance)s:\n"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/login_notice.txt
|
||||
msgid "Browser"
|
||||
msgstr ""
|
||||
msgstr "Navegador"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/login_notice.txt
|
||||
msgid "Operating system"
|
||||
msgstr ""
|
||||
msgstr "Sistema operacional"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/login_notice.txt
|
||||
#, python-format
|
||||
@@ -20407,6 +20493,14 @@ msgid ""
|
||||
"Thanks, \n"
|
||||
"The %(instance)s Team\n"
|
||||
msgstr ""
|
||||
"Se foi você, nenhuma ação é necessária.\n"
|
||||
"\n"
|
||||
"Se você não reconhece este acesso, altere sua senha imediatamente:\n"
|
||||
"\n"
|
||||
"%(url)s\n"
|
||||
"\n"
|
||||
"Obrigado,\n"
|
||||
"Equipe %(instance)s\n"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email/security_notice.txt
|
||||
#, fuzzy, python-format
|
||||
@@ -22387,6 +22481,9 @@ msgid ""
|
||||
"debugging problems in your pretix installation, and verifying that your "
|
||||
"usage of pretix is in compliance with the Enterprise license you purchased."
|
||||
msgstr ""
|
||||
"Isso tem duas finalidades: coletar informações úteis que possam ajudar a "
|
||||
"diagnosticar problemas na sua instalação do pretix e verificar se o uso do "
|
||||
"pretix está em conformidade com a licença Enterprise que você adquiriu."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/global_sysreport.html
|
||||
msgid "First month of license term:"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
|
||||
"PO-Revision-Date: 2026-03-25 08:00+0000\n"
|
||||
"Last-Translator: Renne Rocha <renne@rocha.dev.br>\n"
|
||||
"PO-Revision-Date: 2026-10-30 03:00+0000\n"
|
||||
"Last-Translator: vihumelo <victordimelo@gmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
|
||||
"pretix/pretix-js/pt_BR/>\n"
|
||||
"Language: pt_BR\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.16.2\n"
|
||||
"X-Generator: Weblate 2026.10.1\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js
|
||||
msgid "Marked as paid"
|
||||
@@ -430,7 +430,7 @@ msgstr "Pressione Ctrl+C para copiar!"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules/App.vue
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
msgstr "Editar"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules/App.vue
|
||||
msgid "Visualize"
|
||||
|
||||
@@ -196,6 +196,14 @@ OPTIONS = OrderedDict([
|
||||
'offsets': [46 * mm, 46 * mm],
|
||||
'pagesize': pagesizes.A4,
|
||||
}),
|
||||
('herma_75x40', {
|
||||
'name': 'HERMA 75 x 40 mm (9010)',
|
||||
'cols': 2,
|
||||
'rows': 6,
|
||||
'margins': [28.5 * mm, 25 * mm, 28.5 * mm, 25 * mm],
|
||||
'offsets': [85 * mm, 40 * mm],
|
||||
'pagesize': pagesizes.A4,
|
||||
}),
|
||||
('herma_88.9x33.87', {
|
||||
'name': 'HERMA 88,9 x 33,87 mm (4515)',
|
||||
'cols': 2,
|
||||
|
||||
@@ -219,6 +219,11 @@ TEMPLATES = {
|
||||
"pagesize": (75 * mm, 52 * mm),
|
||||
"layout": _simple_template(75 * mm, 52 * mm),
|
||||
},
|
||||
"75x40": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=75, height=40),
|
||||
"pagesize": (75 * mm, 40 * mm),
|
||||
"layout": _simple_template(75 * mm, 40 * mm),
|
||||
},
|
||||
"70x36": {
|
||||
"label": format_lazy(_("{width} x {height} mm label"), width=70, height=36),
|
||||
"pagesize": (70 * mm, 36 * mm),
|
||||
|
||||
@@ -239,7 +239,7 @@ class ActionView(View):
|
||||
})
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
u = request.GET.get('query', '')
|
||||
u = request.GET.get('query', '').strip()
|
||||
if len(u) < 2:
|
||||
return JsonResponse({'results': []})
|
||||
|
||||
|
||||
@@ -98,19 +98,32 @@ class TicketLayoutSerializer(I18nAwareModelSerializer):
|
||||
return d
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get('default') and self.context['event'].ticket_layouts.filter(default=True).exists:
|
||||
if attrs.get('default') and self.context['event'].ticket_layouts.filter(default=True).exists():
|
||||
raise ValidationError('You cannot have two layouts with default = True')
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data["event"] = self.context["event"]
|
||||
return super().create(validated_data)
|
||||
background = validated_data.pop("background", None)
|
||||
instance = super().create(validated_data)
|
||||
if background:
|
||||
instance.background.save('background.pdf', background)
|
||||
return instance
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
background = validated_data.pop("background", None)
|
||||
if background:
|
||||
if instance.background and TicketLayout.objects.filter(background=instance.background).count() == 1:
|
||||
instance.background.delete()
|
||||
instance.background.save('background.pdf', background)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class TicketLayoutViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = TicketLayoutSerializer
|
||||
queryset = TicketLayout.objects.none()
|
||||
lookup_field = 'id'
|
||||
write_permission = 'event.settings.general:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.ticket_layouts.all()
|
||||
|
||||
@@ -235,6 +235,7 @@ class LayoutGetDefault(EventPermissionRequiredMixin, View):
|
||||
|
||||
|
||||
class LayoutEditorView(BaseEditorView):
|
||||
checkin_qr_warning = True
|
||||
|
||||
@cached_property
|
||||
def layout(self):
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import sys
|
||||
from collections import Counter
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
@@ -472,3 +473,11 @@ def _item_num_options(item):
|
||||
|
||||
def get_item_option_count(items):
|
||||
return sum(_item_num_options(item) for item in items)
|
||||
|
||||
|
||||
def get_item_var_sums(positions, subevent):
|
||||
itemvarsums = Counter()
|
||||
for pos in positions:
|
||||
if pos.subevent == subevent:
|
||||
itemvarsums[pos.variation or pos.item] += 1
|
||||
return itemvarsums
|
||||
@@ -55,7 +55,7 @@
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
{% for provider in request.organizer.sso_providers.all %}
|
||||
{% if provider.is_active %}
|
||||
<a href="{% eventurl request.organizer "presale:organizer.customer.login" provider=provider.pk %}?next={% if request.domain_mode == 'event' or request.domain_mode == 'organizer_alternative' %}{{ request.scheme }}://{{ request.get_host }}{% endif %}{{ request.get_full_path|urlencode }}"
|
||||
<a href="{% abseventurl request.organizer "presale:organizer.customer.login" provider=provider.pk %}?next={% if request.domain_mode == 'event' or request.domain_mode == 'organizer_alternative' %}{{ request.scheme }}://{{ request.get_host }}{% endif %}{{ request.get_full_path|urlencode }}"
|
||||
class="btn btn-primary btn-lg btn-block" data-open-in-popup-window>
|
||||
{{ provider.button_label }}
|
||||
</a>
|
||||
|
||||
@@ -125,10 +125,10 @@
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
<h{{ headline_level|default:3|add:2 }} class="h5" id="{{ form_prefix }}item-{{ item.pk }}-{{ var.pk }}-legend">
|
||||
{{ var }}
|
||||
{% if cart.itemvarsums|getitem:var %}
|
||||
{% if itemvarsums|getitem:var %}
|
||||
<span class="textbubble-success">
|
||||
{% icon "shopping-cart" %}
|
||||
{% blocktrans trimmed count amount=cart.itemvarsums|getitem:var %}
|
||||
{% blocktrans trimmed count amount=itemvarsums|getitem:var %}
|
||||
{{ amount }}× in your cart
|
||||
{% plural %}
|
||||
{{ amount }}× in your cart
|
||||
@@ -299,10 +299,10 @@
|
||||
<div class="product-description {% if item.picture %}with-picture{% endif %}">
|
||||
<h{{ headline_level|default:3|add:1 }} class="h4" id="{{ form_prefix }}item-{{ item.pk }}-legend">
|
||||
{{ item.name }}
|
||||
{% if cart.itemvarsums|getitem:item %}
|
||||
{% if itemvarsums|getitem:item %}
|
||||
<span class="textbubble-success">
|
||||
{% icon "shopping-cart" %}
|
||||
{% blocktrans trimmed count amount=cart.itemvarsums|getitem:item %}
|
||||
{% blocktrans trimmed count amount=itemvarsums|getitem:item %}
|
||||
{{ amount }}× in your cart
|
||||
{% plural %}
|
||||
{{ amount }}× in your cart
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
import copy
|
||||
import warnings
|
||||
from collections import Counter, defaultdict
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from functools import wraps
|
||||
@@ -266,10 +266,6 @@ class CartMixin:
|
||||
minutes_left = None
|
||||
seconds_left = None
|
||||
|
||||
itemvarsums = Counter()
|
||||
for p in cartpos:
|
||||
itemvarsums[p.variation or p.item] += 1
|
||||
|
||||
return {
|
||||
'positions': positions,
|
||||
'invoice_address': self.invoice_address,
|
||||
@@ -291,7 +287,6 @@ class CartMixin:
|
||||
not self.request.event.settings.display_net_prices and
|
||||
sum(c.price_includes_rounding_correction for c in positions) + sum(f.price_includes_rounding_correction for f in fees)
|
||||
),
|
||||
'itemvarsums': itemvarsums,
|
||||
'current_selected_payments': [
|
||||
p for p in self.current_selected_payments(lcp, fees, self.invoice_address)
|
||||
if p.get('multi_use_supported')
|
||||
|
||||
@@ -70,7 +70,8 @@ from pretix.helpers.http import redirect_to_url
|
||||
from pretix.helpers.safedownload import check_token
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
from pretix.presale.productlist import (
|
||||
get_item_option_count, item_group_by_category, prepare_item_list_for_shop,
|
||||
get_item_option_count, get_item_var_sums, item_group_by_category,
|
||||
prepare_item_list_for_shop,
|
||||
)
|
||||
from pretix.presale.views import (
|
||||
CartMixin, EventViewMixin, allow_cors_if_namespaced,
|
||||
@@ -701,6 +702,7 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, CartMixin, TemplateView
|
||||
)
|
||||
|
||||
context['cart'] = self.get_cart()
|
||||
context['itemvarsums'] = get_item_var_sums(context['cart'].get('raw', []), self.subevent)
|
||||
context['show_cart'] = context['cart']['positions']
|
||||
|
||||
# Regroup those by category
|
||||
|
||||
@@ -156,7 +156,7 @@ class LoginView(RedirectBackMixin, FormView):
|
||||
"""Security check complete. Log the user in."""
|
||||
customer = form.get_customer()
|
||||
customer_login(self.request, customer)
|
||||
customer_signed_in.send(customer.organizer, customer=customer)
|
||||
customer_signed_in.send(customer.organizer, customer=customer, profile=None)
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
|
||||
@@ -901,7 +901,7 @@ class SSOLoginReturnView(RedirectBackMixin, View):
|
||||
popup_origin
|
||||
)
|
||||
|
||||
customer_signed_in.send(customer.organizer, customer=customer)
|
||||
customer_signed_in.send(customer.organizer, customer=customer, profile=profile)
|
||||
|
||||
if popup_origin:
|
||||
return render(self.request, 'pretixpresale/postmessage.html', {
|
||||
|
||||
@@ -72,7 +72,8 @@ from pretix.helpers.http import redirect_to_url
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
from pretix.presale.ical import get_public_ical
|
||||
from pretix.presale.productlist import (
|
||||
get_item_option_count, item_group_by_category, prepare_item_list_for_shop,
|
||||
get_item_option_count, get_item_var_sums, item_group_by_category,
|
||||
prepare_item_list_for_shop,
|
||||
)
|
||||
from pretix.presale.signals import seatingframe_html_head
|
||||
from pretix.presale.views.organizer import (
|
||||
@@ -244,6 +245,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
context['display_add_to_cart'] = display_add_to_cart
|
||||
|
||||
context['cart'] = self.get_cart()
|
||||
context['itemvarsums'] = get_item_var_sums(context['cart'].get('raw', []), self.subevent)
|
||||
context['has_addon_choices'] = any(cp.has_addon_choices for cp in get_cart(self.request))
|
||||
|
||||
templating_context = PlaceholderContext(event_or_subevent=self.subevent or self.request.event, event=self.request.event)
|
||||
|
||||
@@ -76,7 +76,7 @@ from pretix.base.models.tax import TaxedPrice
|
||||
from pretix.base.payment import PaymentException
|
||||
from pretix.base.services.invoices import (
|
||||
generate_cancellation, generate_invoice, invoice_pdf, invoice_pdf_task,
|
||||
invoice_qualified,
|
||||
invoice_qualified, transmit_invoice,
|
||||
)
|
||||
from pretix.base.services.orders import (
|
||||
OrderChangeManager, OrderError, _try_auto_refund, cancel_order,
|
||||
@@ -907,6 +907,9 @@ class OrderModify(EventViewMixin, OrderDetailMixin, OrderQuestionsViewMixin, Tem
|
||||
self.order.log_action('pretix.event.order.invoice.reissued', data={
|
||||
'invoice': inv.pk
|
||||
})
|
||||
transmit_invoice.apply_async(args=(c.event_id, c.pk, True))
|
||||
if c.pk != inv.pk:
|
||||
transmit_invoice.apply_async(args=(inv.event_id, inv.pk, True))
|
||||
messages.success(self.request, _('The invoice has been reissued.'))
|
||||
except Exception as e:
|
||||
self.order.log_action("pretix.event.order.invoice.failed", data={
|
||||
|
||||
@@ -35,6 +35,7 @@ import calendar
|
||||
import hashlib
|
||||
import math
|
||||
import operator
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from functools import reduce
|
||||
@@ -381,7 +382,11 @@ class EventListMixin:
|
||||
def _set_week_year(self):
|
||||
if 'date' in self.request.GET:
|
||||
try:
|
||||
iso = dateutil.parser.isoparse(self.request.GET.get('date')).isocalendar()
|
||||
input = self.request.GET.get('date')
|
||||
# Our parameters for the single-digit weeks of the year are 2027-W2, as emitted by Django's "W" format code,
|
||||
# but dateutil 4.0 is strict about ISO and only accepts 2027-W02 as valid.
|
||||
input = re.sub('-W([0-9])$', '-W0\\1', input)
|
||||
iso = dateutil.parser.isoparse(input).isocalendar()
|
||||
except ValueError:
|
||||
iso = time_machine_now().isocalendar()
|
||||
self.year = iso[0]
|
||||
|
||||
+35
-1
@@ -19,12 +19,18 @@
|
||||
# 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/>.
|
||||
#
|
||||
import re
|
||||
import typing
|
||||
import weakref
|
||||
|
||||
from celery.exceptions import Retry
|
||||
from sentry_sdk import Hub
|
||||
from sentry_sdk.integrations import django as djangosentry
|
||||
from sentry_sdk.utils import capture_internal_exceptions
|
||||
from sentry_sdk.scrubber import EventScrubber
|
||||
from sentry_sdk.utils import AnnotatedValue, capture_internal_exceptions
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from sentry_sdk._types import Event
|
||||
|
||||
|
||||
def _make_event_processor(weak_request, integration):
|
||||
@@ -96,3 +102,31 @@ def setup_custom_filters():
|
||||
hub = Hub.current
|
||||
with hub.configure_scope() as scope:
|
||||
scope.add_event_processor(ignore_retry)
|
||||
|
||||
|
||||
class PretixEventScrubber(EventScrubber):
|
||||
secret_re = re.compile(
|
||||
'.*(pretixsecret|ramiiosecret|PRIVATE KEY|://[^/@:]*:[^/@:]+@).*',
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
def scrub_dict(self, d: object) -> None:
|
||||
if not isinstance(d, dict):
|
||||
return
|
||||
|
||||
super().scrub_dict(d)
|
||||
self._scrub_dict_for_known_secrets(d)
|
||||
|
||||
def _scrub_dict_for_known_secrets(self, d: dict):
|
||||
for k, v in d.items():
|
||||
if isinstance(v, str) and self.secret_re.match(v):
|
||||
d[k] = AnnotatedValue.substituted_because_contains_sensitive_data()
|
||||
|
||||
def scrub_exception(self, event: "Event") -> None:
|
||||
with capture_internal_exceptions():
|
||||
if "exception" in event:
|
||||
self.scrub_dict(event["exception"])
|
||||
|
||||
def scrub_event(self, event: "Event") -> None:
|
||||
super().scrub_event(event)
|
||||
self.scrub_exception(event)
|
||||
@@ -41,7 +41,7 @@ from json import loads
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import importlib_metadata as metadata
|
||||
from importlib import metadata
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.crypto import get_random_string
|
||||
from kombu import Queue
|
||||
@@ -721,9 +721,9 @@ if config.has_option('sentry', 'dsn') and not any(c in sys.argv for c in ('shell
|
||||
from sentry_sdk.integrations.logging import (
|
||||
LoggingIntegration, ignore_logger,
|
||||
)
|
||||
from sentry_sdk.scrubber import DEFAULT_DENYLIST, EventScrubber
|
||||
from sentry_sdk.scrubber import DEFAULT_DENYLIST
|
||||
|
||||
from .sentry import PretixSentryIntegration, setup_custom_filters
|
||||
from .sentry import PretixSentryIntegration, PretixEventScrubber, setup_custom_filters
|
||||
|
||||
SENTRY_TOKEN = config.get('sentry', 'traces_sample_token', fallback='')
|
||||
SENTRY_ENABLE_LOGS = config.getboolean('sentry', 'enable_logs', fallback=False)
|
||||
@@ -759,7 +759,7 @@ if config.has_option('sentry', 'dsn') and not any(c in sys.argv for c in ('shell
|
||||
traces_sampler=traces_sampler,
|
||||
environment=urlparse(SITE_URL).netloc,
|
||||
release=__version__,
|
||||
event_scrubber=EventScrubber(denylist=pretix_denylist, recursive=True),
|
||||
event_scrubber=PretixEventScrubber(denylist=pretix_denylist, recursive=True),
|
||||
send_default_pii=False,
|
||||
propagate_traces=False, # see https://github.com/getsentry/sentry-python/issues/1717
|
||||
)
|
||||
|
||||
@@ -618,18 +618,21 @@ var editor = {
|
||||
$('#loading-initial').remove()
|
||||
})
|
||||
}
|
||||
editor._update_version_notice()
|
||||
editor._update_notices()
|
||||
},
|
||||
|
||||
_update_version_notice: function () {
|
||||
_update_notices: function () {
|
||||
$('#version-notice').toggle(
|
||||
editor._other_page_objects.some((o) => o.type === 'textcontainer')
|
||||
|| editor.fabric.getObjects().some((o) => o.type === 'textcontainer')
|
||||
)
|
||||
$('#nocheckin-notice').toggle(
|
||||
!editor.fabric.getObjects().some((o) => o.type === 'barcodearea' && (!o.content || o.content === 'secret'))
|
||||
)
|
||||
},
|
||||
|
||||
_update_toolbox_values: function () {
|
||||
editor._update_version_notice()
|
||||
editor._update_notices()
|
||||
let o = editor.fabric.getActiveObject()
|
||||
if (!o) {
|
||||
return
|
||||
@@ -898,6 +901,7 @@ var editor = {
|
||||
|
||||
o.setCoords()
|
||||
editor.fabric.renderAll()
|
||||
editor._update_notices()
|
||||
},
|
||||
|
||||
_update_toolbox: function () {
|
||||
|
||||
@@ -103,3 +103,6 @@ body {
|
||||
.panel-pdf-editor .panel-heading form > .btn-group {
|
||||
margin-right: 1em;
|
||||
}
|
||||
#nocheckin-notice {
|
||||
display: none;
|
||||
}
|
||||
@@ -25,8 +25,10 @@ import tempfile
|
||||
|
||||
tmpdir = tempfile.TemporaryDirectory()
|
||||
os.environ.setdefault('DATA_DIR', tmpdir.name)
|
||||
if os.path.exists('test/sqlite.cfg'):
|
||||
os.environ.setdefault('PRETIX_CONFIG_FILE', 'test/sqlite.cfg')
|
||||
if os.path.exists('tests/ci_sqlite.cfg'):
|
||||
os.environ.setdefault('PRETIX_CONFIG_FILE', 'tests/ci_sqlite.cfg')
|
||||
else:
|
||||
os.environ.setdefault("PRETIX_CONFIG_FILE", "")
|
||||
|
||||
from pretix.settings import * # NOQA
|
||||
|
||||
@@ -100,3 +102,4 @@ class DisableMigrations(object):
|
||||
|
||||
if not os.environ.get("GITHUB_WORKFLOW", ""):
|
||||
MIGRATION_MODULES = DisableMigrations()
|
||||
VITE_DEV_MODE = True
|
||||
@@ -26,6 +26,7 @@ from unittest import mock
|
||||
|
||||
import pytest
|
||||
from django.core import mail as djmail
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils.timezone import now
|
||||
from django_countries.fields import Country
|
||||
@@ -248,7 +249,14 @@ def test_order_update_state_validation(token_client, organizer, event, order):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_update_transmission_validation(token_client, organizer, event, order):
|
||||
def test_order_update_transmission_validation(token_client, organizer, event, order, monkeypatch):
|
||||
def mock_validate(self, value):
|
||||
if value == "9930:DE111111111":
|
||||
return value
|
||||
raise ValidationError("Invalid")
|
||||
|
||||
monkeypatch.setattr("pretix.base.invoicing.peppol.PeppolIdValidator._validate_peppol_id_online", mock_validate)
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
@@ -374,7 +382,7 @@ def test_order_update_transmission_validation(token_client, organizer, event, or
|
||||
"vat_id": "",
|
||||
"transmission_type": "peppol",
|
||||
"transmission_info": {
|
||||
"transmission_peppol_participant_id": "9930:DE811569869",
|
||||
"transmission_peppol_participant_id": "9930:DE111111111",
|
||||
"ignored": "parameter",
|
||||
},
|
||||
}
|
||||
@@ -384,7 +392,7 @@ def test_order_update_transmission_validation(token_client, organizer, event, or
|
||||
order.invoice_address.refresh_from_db()
|
||||
assert order.invoice_address.transmission_type == "peppol"
|
||||
assert order.invoice_address.transmission_info == {
|
||||
"transmission_peppol_participant_id": "9930:DE811569869",
|
||||
"transmission_peppol_participant_id": "9930:DE111111111",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -94,6 +94,83 @@ def question(event, item):
|
||||
return q
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_log_action_filter(event, order):
|
||||
sensitivekeys = [
|
||||
'auth',
|
||||
'key',
|
||||
'token',
|
||||
'password',
|
||||
'Password',
|
||||
'_pass',
|
||||
'salt',
|
||||
'secret',
|
||||
]
|
||||
log_data = log_data_filtered = {
|
||||
'foo': 'bar',
|
||||
}
|
||||
for d in (log_data, log_data_filtered):
|
||||
value = '********' if d == log_data_filtered else '__sensitive_info__'
|
||||
for k in sensitivekeys:
|
||||
d[k] = d['prefix' + k] = d['prefix' + k + 'suffix'] = d[k + 'suffix'] = value
|
||||
|
||||
d['recursive_dict'] = {
|
||||
'test': 'dummy',
|
||||
'test_token': value,
|
||||
'd': {
|
||||
'baz': 'foo',
|
||||
'mypassword': value,
|
||||
'l': [
|
||||
'foo',
|
||||
'bar',
|
||||
{
|
||||
'baz': True,
|
||||
'superkey': value,
|
||||
},
|
||||
],
|
||||
},
|
||||
'l': [
|
||||
'okay',
|
||||
{
|
||||
'salt_to_secret': value,
|
||||
'name': 'okay'
|
||||
},
|
||||
'element',
|
||||
[
|
||||
'another',
|
||||
{
|
||||
'api_password': value,
|
||||
},
|
||||
'list'
|
||||
]
|
||||
]
|
||||
}
|
||||
d['recursive_list'] = [
|
||||
'foo',
|
||||
'bar',
|
||||
[
|
||||
'foo',
|
||||
'bar',
|
||||
{
|
||||
'foo': 'bar',
|
||||
'api_token': value,
|
||||
},
|
||||
'baz',
|
||||
],
|
||||
{
|
||||
'foo': 'bar',
|
||||
'MyPassword': value,
|
||||
}
|
||||
]
|
||||
l1 = order.log_action(
|
||||
'dummy.log',
|
||||
data=log_data,
|
||||
)
|
||||
|
||||
l1.refresh_from_db()
|
||||
assert json.loads(l1.data) == log_data_filtered
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_email_shredder(event, order):
|
||||
l1 = order.log_action(
|
||||
|
||||
@@ -147,6 +147,7 @@ def test_api_create(env, token_client):
|
||||
assert resp.status_code == 201
|
||||
tl = env[0].ticket_layouts.get(pk=resp.data["id"])
|
||||
assert tl.background
|
||||
assert "cachedfile" not in tl.background.name
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -163,6 +164,21 @@ def test_api_create_validate_default(env, token_client):
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"non_field_errors": ["You cannot have two layouts with default = True"]}
|
||||
|
||||
env[0].ticket_layouts.filter(default=True).update(default=False)
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/ticketlayouts/'.format(env[0].slug, env[0].slug),
|
||||
{
|
||||
'name': 'Foo',
|
||||
'default': True,
|
||||
'layout': [],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
tl = env[0].ticket_layouts.get(pk=resp.data["id"])
|
||||
assert tl.default
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_api_create_validate_layout(env, token_client):
|
||||
@@ -215,6 +231,7 @@ def test_api_update(env, token_client):
|
||||
assert json.loads(env[1].layout) == [
|
||||
{"type": "barcodearea", "left": "7.00", "bottom": "11.15", "size": "45.00", "content": "secret"}
|
||||
]
|
||||
assert "cachedfile" not in env[1].background.name
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -230,6 +247,18 @@ def test_api_update_validate_default(env, token_client):
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"non_field_errors": ["You cannot have two layouts with default = True"]}
|
||||
|
||||
env[0].ticket_layouts.filter(default=True).update(default=False)
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/ticketlayouts/{}/'.format(env[0].slug, env[0].slug, tl2.pk),
|
||||
{
|
||||
"default": True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
tl2.refresh_from_db()
|
||||
assert tl2.default
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_api_delete(env, token_client):
|
||||
@@ -327,3 +356,22 @@ def test_renderer_batch_invalid(env, token_client, position):
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"parts": ["Please do not submit more than 1000 parts."]}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_api_permission(env, token_client):
|
||||
t = env[0].organizer.teams.get()
|
||||
t.limit_event_permissions = {"event.orders:read": True}
|
||||
t.all_event_permissions = False
|
||||
t.save()
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/ticketlayouts/{}/'.format(env[0].slug, env[0].slug, env[1].pk),
|
||||
{
|
||||
"name": "Bar",
|
||||
"layout": [
|
||||
{"type": "barcodearea", "left": "7.00", "bottom": "11.15", "size": "45.00", "content": "secret"}
|
||||
]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 403
|
||||
@@ -193,7 +193,7 @@ def test_org_login_logout(env, client, mocker):
|
||||
})
|
||||
assert r.status_code == 302
|
||||
|
||||
customer_signed_in.send.assert_called_once_with(customer.organizer, customer=customer)
|
||||
customer_signed_in.send.assert_called_once_with(customer.organizer, customer=customer, profile=None)
|
||||
|
||||
r = client.get('/bigevents/account/')
|
||||
assert r.status_code == 200
|
||||
@@ -349,7 +349,10 @@ def test_org_sso_login_new_customer(env, client, provider, mocker):
|
||||
c = Customer.objects.get(provider=provider)
|
||||
assert c.external_identifier == "abcdf"
|
||||
customer_created.send.assert_called_once_with(c.organizer, customer=c)
|
||||
customer_signed_in.send.assert_called_once_with(c.organizer, customer=c)
|
||||
customer_signed_in.send.assert_called_once_with(c.organizer, customer=c, profile={
|
||||
'uid': 'abcdf', 'email': 'test@example.org',
|
||||
'oidc_claims': {'sub': 'abcdf', 'email': 'test@example.org'},
|
||||
})
|
||||
|
||||
r = client.get('/bigevents/account/')
|
||||
assert r.status_code == 200
|
||||
@@ -401,7 +404,10 @@ def test_org_sso_login_returning_customer_new_email(env, client, provider, mocke
|
||||
_sso_login(client, provider)
|
||||
with scopes_disabled():
|
||||
c = Customer.objects.get(provider=provider)
|
||||
customer_signed_in.send.assert_called_once_with(c.organizer, customer=c)
|
||||
customer_signed_in.send.assert_called_once_with(c.organizer, customer=c, profile={
|
||||
'uid': 'abcdf', 'email': 'test@example.org',
|
||||
'oidc_claims': {'sub': 'abcdf', 'email': 'test@example.org'},
|
||||
})
|
||||
customer_signed_in.send.reset_mock()
|
||||
|
||||
r = client.get('/bigevents/account/logout')
|
||||
@@ -410,7 +416,10 @@ def test_org_sso_login_returning_customer_new_email(env, client, provider, mocke
|
||||
_sso_login(client, provider, 'new@example.net')
|
||||
c.refresh_from_db()
|
||||
assert c.email == "new@example.net"
|
||||
customer_signed_in.send.assert_called_once_with(c.organizer, customer=c)
|
||||
customer_signed_in.send.assert_called_once_with(c.organizer, customer=c, profile={
|
||||
'uid': 'abcdf', 'email': 'new@example.net',
|
||||
'oidc_claims': {'sub': 'abcdf', 'email': 'new@example.net'},
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
|
||||
@@ -1393,6 +1393,61 @@ class OrderChangeAddonsTest(BaseOrdersTest):
|
||||
assert a.item == self.workshop2
|
||||
assert a.variation == self.workshop2a
|
||||
|
||||
def test_quota_sold_out_change_hide_sold_out(self):
|
||||
self.event.settings.hide_sold_out = True
|
||||
self.workshopquota.size = 1
|
||||
self.workshopquota.items.remove(self.workshop2)
|
||||
self.workshopquota.variations.remove(self.workshop2a)
|
||||
self.workshopquota.variations.remove(self.workshop2b)
|
||||
self.workshopquota.save()
|
||||
self.workshopquota2 = Quota.objects.create(event=self.event, name='Workshop 2', size=5)
|
||||
self.workshopquota2.items.add(self.workshop2)
|
||||
self.workshopquota2.variations.add(self.workshop2a)
|
||||
self.workshopquota2.variations.add(self.workshop2b)
|
||||
|
||||
with scopes_disabled():
|
||||
OrderPosition.objects.create(
|
||||
order=self.order,
|
||||
item=self.workshop1,
|
||||
variation=None,
|
||||
price=Decimal("12"),
|
||||
addon_to=self.ticket_pos,
|
||||
attendee_name_parts={'full_name': "Peter"}
|
||||
)
|
||||
self.order.total += Decimal("12")
|
||||
self.order.save()
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert 'Workshop 1' in response.content.decode()
|
||||
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['checked']
|
||||
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{
|
||||
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
||||
},
|
||||
follow=True
|
||||
)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert 'alert-danger' not in response.content.decode()
|
||||
|
||||
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
||||
form_data['confirm'] = 'true'
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
||||
)
|
||||
assert 'alert-success' in response.content.decode()
|
||||
|
||||
with scopes_disabled():
|
||||
a = self.ticket_pos.addons.get(canceled=False)
|
||||
assert a.item == self.workshop2
|
||||
assert a.variation == self.workshop2a
|
||||
|
||||
def _assert_ws2a_not_allowed(self):
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
|
||||
@@ -422,37 +422,42 @@ class OrdersTest(BaseOrdersTest):
|
||||
with scopes_disabled():
|
||||
assert self.order.invoices.count() == 1
|
||||
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'zipcode': '12345',
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret),
|
||||
target_status_code=200)
|
||||
with self.captureOnCommitCallbacks(execute=True):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'zipcode': '12345',
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret),
|
||||
target_status_code=200)
|
||||
with scopes_disabled():
|
||||
assert self.order.invoices.count() == 3
|
||||
last_two = self.order.invoices.order_by('-pk')[:2]
|
||||
for inv in last_two:
|
||||
assert inv.transmission_status != Invoice.TRANSMISSION_STATUS_PENDING
|
||||
|
||||
self.event.settings.set('invoice_reissue_after_modify', False)
|
||||
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'zipcode': '54321',
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret),
|
||||
target_status_code=200)
|
||||
with self.captureOnCommitCallbacks(execute=True):
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
||||
'%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC',
|
||||
'zipcode': '54321',
|
||||
'street': 'Main Street',
|
||||
'city': 'Heidelberg',
|
||||
'country': 'DE',
|
||||
'transmission_type': 'email',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response,
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.order.secret),
|
||||
target_status_code=200)
|
||||
with scopes_disabled():
|
||||
assert self.order.invoices.count() == 3
|
||||
|
||||
|
||||
Reference in new issue
Block a user