Compare commits

..

1 Commits

Author SHA1 Message Date
luelista
2c74116b73 Document datasync_providers registry 2025-08-19 11:47:42 +02:00
1061 changed files with 238106 additions and 363909 deletions

View File

@@ -1,7 +1,7 @@
This file is part of pretix (Community Edition).
Copyright (C) 2014-2020 Raphael Michel and contributors
Copyright (C) 2020-today pretix GmbH and contributors
Copyright (C) 2014-2020 Raphael Michel and contributors
Copyright (C) 2020-2021 rami.io GmbH and contributors
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -421,94 +421,3 @@ Annulment of a check-in
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
:statuscode 404: The requested nonce does not exist.
Check-in history
----------------
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the check-in
successful boolean Whether the check-in was successful
error_reason string Category of reason why the check-in was unsuccessful. Currently
``"canceled"``, ``"invalid"``, ``"unpaid"`` ``"product"``,
``"rules"``, ``"revoked"``, ``"incomplete"``, ``"already_redeemed"``,
``"ambiguous"``, ``"error"``, ``"blocked"``, ``"unapproved"``,
``"invalid_time"``, ``"annulled"`` or ``null``
error_explanation string Additional, human-readable reason for the check-in to be unsuccessful (or ``null``)
position integer Internal ID of the order position (or ``null`` for unknown scans)
datetime datetime Logical time when the check-in happened
created datetime Time when the check-in appeared on the server
list integer Internal ID of the check-in list
auto_checked_in boolean Whether the check-in was performed by the system automatically
gate integer Internal ID of the gate (or ``null``)
device integer Internal ID of the device (or ``null``)
device_id integer Organizer-internal ID of the device (or ``null``)
type string Type of check-in, currently ``"entry"`` or ``"exit"``
===================================== ========================== =======================================================
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkins/
Returns a list of all check-in events within a given event.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/checkins/ 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,
"successful": true,
"error_reason": null,
"error_explanation": null,
"position": 1234,
"datetime": "2017-12-25T12:45:23Z",
"created": "2017-12-25T12:45:23Z",
"list": 2,
"auto_checked_in": false,
"gate": null,
"device": null,
"device_id": null,
"type": "entry",
}
]
}
:query integer page: The page number in case of a multi-page result set, default is 1
:query datetime created_since: Only return check-ins that have been created since the given date (inclusive).
:query datetime created_before: Only return check-ins that have been created before the given date (exclusive).
:query datetime datetime_since: Only return check-ins that have happened since the given date (inclusive).
:query datetime datetime_before: Only return check-ins that have happened before the given date (exclusive).
:query boolean successful: Only return check-ins that have (not) been successful.
:query boolean error_reason: Only return check-ins with a specific error reason.
:query integer list: Only return check-ins from a specific list.
:query string type: Only return check-ins of a specific type.
:query integer gate: Only return check-ins from a specific gate.
:query integer device: Only return check-ins from a specific device.
:query boolean auto_checked_in: Only return check-ins that are (not) auto-checked in.
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``datetime``, ``created``,
and ``id``.
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.

View File

@@ -19,7 +19,6 @@ at :ref:`plugin-docs`.
item_bundles
item_add-ons
item_meta_properties
item_program_times
questions
question_options
quotas

View File

@@ -22,13 +22,10 @@ invoice_from_name string Sender address:
invoice_from string Sender address: Address lines
invoice_from_zipcode string Sender address: ZIP code
invoice_from_city string Sender address: City
invoice_from_state string Sender address: State (only used in some countries)
invoice_from_country string Sender address: Country code
invoice_from_tax_id string Sender address: Local Tax ID
invoice_from_vat_id string Sender address: EU VAT ID
invoice_to string Full recipient address
invoice_to_is_business boolean Recipient address: Business vs individual (``null`` for
invoices created before pretix 2025.6).
invoice_to_company string Recipient address: Company name
invoice_to_name string Recipient address: Person name
invoice_to_street string Recipient address: Address lines
@@ -38,7 +35,6 @@ invoice_to_state string Recipient addre
invoice_to_country string Recipient address: Country code
invoice_to_vat_id string Recipient address: EU VAT ID
invoice_to_beneficiary string Invoice beneficiary
invoice_to_transmission_info object Additional transmission info (see :ref:`rest-transmission-types`)
custom_field string Custom invoice address field
date date Invoice date
refers string Invoice number of an invoice this invoice refers to
@@ -81,12 +77,17 @@ lines list of objects The actual invo
for all invoice lines
created before this field was introduced as well as for
all lines not created by a fee (e.g. a product).
period_start datetime Start date of the service or delivery period of the invoice line.
Can be ``null`` if not known.
├ period_end datetime End date of the service or delivery period of the invoice line.
Can be ``null`` if not known.
├ event_date_from datetime Deprecated alias of ``period_start``.
├ event_date_to datetime Deprecated alias of ``period_end``.
event_date_from datetime Start date of the (sub)event this line was created for as it
was set during invoice creation. Can be ``null`` for all invoice
lines created before this was introduced as well as for lines in
an event series not created by a product (e.g. shipping or
cancellation fees).
├ event_date_to datetime End date of the (sub)event this line was created for as it
was set during invoice creation. Can be ``null`` for all invoice
lines created before this was introduced as well as for lines in
an event series not created by a product (e.g. shipping or
cancellation fees) as well as whenever the respective (sub)event
has no end date set.
├ event_location string Location of the (sub)event this line was created for as it
was set during invoice creation. Can be ``null`` for all invoice
lines created before this was introduced as well as for lines in
@@ -109,12 +110,6 @@ foreign_currency_rate decimal (string) If ``foreign_cu
foreign_currency_rate_date date If ``foreign_currency_rate`` is set, this signifies the
date at which the currency rate was obtained.
internal_reference string Customer's reference to be printed on the invoice.
transmission_type string Requested transmission channel (see :ref:`rest-transmission-types`)
transmission_provider string Selected transmission provider (depends on installed
plugins). ``null`` if not yet chosen.
transmission_status string Transmission status, one of ``unknown`` (pre-2025.6),
``pending``, ``inflight``, ``failed``, and ``completed``.
transmission_date datetime Time of last change in transmission status (may be ``null``).
===================================== ========================== =======================================================
@@ -126,76 +121,6 @@ transmission_date datetime Time of last ch
The ``tax_code`` attribute has been added.
.. versionchanged:: 2025.6
The attributes ``invoice_to_is_business``, ``invoice_to_transmission_info``, ``transmission_type``,
``transmission_provider``, ``transmission_status``, and ``transmission_date`` have been added.
.. _`rest-transmission-types`:
Transmission types
------------------
pretix supports multiple ways to transmit an invoice from the organizer to the invoice recipient.
For each transmission type, different fields are supported in the ``transmission_info`` object of the
invoice address. Currently, pretix supports the following transmission types:
Email
"""""
The identifier ``"email"`` represents the transmission of PDF invoices through email.
This is the default transmission type in pretix and has some special behavior for backwards compatibility.
Transmission is always executed through the provider ``"email_pdf"``.
The ``transmission_info`` object may contain the following properties:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
transmission_email_address string Optional. An email address other than the order address
that the invoice should be sent to.
Business customers only.
===================================== ========================== =======================================================
Peppol
""""""
The identifier ``"peppol"`` represents the transmission of XML invoices through the `Peppol`_ network.
This is only available for business addresses.
This is not supported by pretix out of the box and requires the use of a suitable plugin.
The ``transmission_info`` object may contain the following properties:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
transmission_peppol_participant_id string Required. The Peppol participant ID of the recipient.
===================================== ========================== =======================================================
Italian Exchange System
"""""""""""""""""""""""
The identifier ``"it_sdi"`` represents the transmission of XML invoices through the `Sistema di Interscambio`_ network used in Italy.
This is only available for addresses with country ``"IT"``.
This is not supported by pretix out of the box and requires the use of a suitable plugin.
The ``transmission_info`` object may contain the following properties:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
transmission_it_sdi_codice_fiscale string Required for non-business address. Fiscal code of the
recipient.
transmission_it_sdi_pec string Required for business addresses. Address for certified
electronic mail.
transmission_it_sdi_recipient_code string Required for businesses. SdI recipient code.
===================================== ========================== =======================================================
If this type is selected, ``vat_id`` is required for business addresses.
List of all invoices
--------------------
@@ -234,13 +159,11 @@ List of all invoices
"invoice_from": "Demo street 12",
"invoice_from_zipcode":"",
"invoice_from_city":"Demo town",
"invoice_from_state":"CA",
"invoice_from_country":"US",
"invoice_from_tax_id":"",
"invoice_from_vat_id":"",
"invoice_to": "Sample company\nJohn Doe\nTest street 12\n12345 Testington\nTestikistan\nVAT-ID: EU123456789",
"invoice_to_company": "Sample company",
"invoice_to_is_business": true,
"invoice_to_name": "John Doe",
"invoice_to_street": "Test street 12",
"invoice_to_zipcode": "12345",
@@ -249,7 +172,6 @@ List of all invoices
"invoice_to_country": "TE",
"invoice_to_vat_id": "EU123456789",
"invoice_to_beneficiary": "",
"invoice_to_transmission_info": {},
"custom_field": null,
"date": "2017-12-01",
"refers": null,
@@ -271,8 +193,6 @@ List of all invoices
"fee_internal_type": null,
"event_date_from": "2017-12-27T10:00:00Z",
"event_date_to": null,
"period_start": "2017-12-27T10:00:00Z",
"period_end": "2017-12-27T10:00:00Z",
"event_location": "Heidelberg",
"attendee_name": null,
"gross_value": "23.00",
@@ -284,11 +204,7 @@ List of all invoices
],
"foreign_currency_display": "PLN",
"foreign_currency_rate": "4.2408",
"foreign_currency_rate_date": "2017-07-24",
"transmission_type": "email",
"transmission_provider": "email_pdf",
"transmission_status": "completed",
"transmission_date": "2017-07-24T10:00:00Z"
"foreign_currency_rate_date": "2017-07-24"
}
]
}
@@ -383,13 +299,11 @@ Fetching individual invoices
"invoice_from": "Demo street 12",
"invoice_from_zipcode":"",
"invoice_from_city":"Demo town",
"invoice_from_state":"CA",
"invoice_from_country":"US",
"invoice_from_tax_id":"",
"invoice_from_vat_id":"",
"invoice_to": "Sample company\nJohn Doe\nTest street 12\n12345 Testington\nTestikistan\nVAT-ID: EU123456789",
"invoice_to_company": "Sample company",
"invoice_to_is_business": true,
"invoice_to_name": "John Doe",
"invoice_to_street": "Test street 12",
"invoice_to_zipcode": "12345",
@@ -398,7 +312,6 @@ Fetching individual invoices
"invoice_to_country": "TE",
"invoice_to_vat_id": "EU123456789",
"invoice_to_beneficiary": "",
"invoice_to_transmission_info": {},
"custom_field": null,
"date": "2017-12-01",
"refers": null,
@@ -420,8 +333,6 @@ Fetching individual invoices
"fee_internal_type": null,
"event_date_from": "2017-12-27T10:00:00Z",
"event_date_to": null,
"period_start": "2017-12-27T10:00:00Z",
"period_end": "2017-12-27T10:00:00Z",
"event_location": "Heidelberg",
"attendee_name": null,
"gross_value": "23.00",
@@ -433,11 +344,7 @@ Fetching individual invoices
],
"foreign_currency_display": "PLN",
"foreign_currency_rate": "4.2408",
"foreign_currency_rate_date": "2017-07-24",
"transmission_type": "email",
"transmission_provider": "email_pdf",
"transmission_status": "completed",
"transmission_date": "2017-07-24T10:00:00Z"
"foreign_currency_rate_date": "2017-07-24"
}
:param organizer: The ``slug`` field of the organizer to fetch
@@ -542,70 +449,3 @@ Invoices cannot be edited directly, but the following actions can be triggered:
:statuscode 400: The invoice has already been canceled
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to change this resource.
Transmitting invoices
---------------------
Invoices are transmitted automatically when created during order creation or payment receipt,
but in other cases transmission may need to be triggered manually.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/invoices/(number)/transmit/
Transmits the invoice to the recipient, but only if it is in ``pending`` state.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/transmit/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
Content-Type: application/pdf
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param number: The ``number`` field of the invoice to transmit
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to transmit this invoice **or** the invoice may not be transmitted
:statuscode 409: The invoice is currently in transmission
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/invoices/(number)/retransmit/
Transmits the invoice to the recipient even if transmission was already attempted previously.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/retransmit/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
Content-Type: application/pdf
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param number: The ``number`` field of the invoice to transmit
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to transmit this invoice **or** the invoice may not be transmitted
:statuscode 409: The invoice is currently in transmission
.. _Peppol: https://en.wikipedia.org/wiki/PEPPOL
.. _Sistema di Interscambio: https://it.wikipedia.org/wiki/Fattura_elettronica_in_Italia

View File

@@ -1,223 +0,0 @@
Item program times
==================
Resource description
--------------------
Program times for products (items) that can be set in addition to event times, e.g. to display seperate schedules within an event.
Note that ``program_times`` are not available for items inside event series.
The program times resource contains the following public fields:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the program time
start datetime The start date time for this program time slot.
end datetime The end date time for this program time slot.
===================================== ========================== =======================================================
.. versionchanged:: TODO
The resource has been added.
Endpoints
---------
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/program_times/
Returns a list of all program times for a given item.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/items/11/program_times/ 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": 3,
"next": null,
"previous": null,
"results": [
{
"id": 2,
"start": "2025-08-14T22:00:00Z",
"end": "2025-08-15T00:00:00Z"
},
{
"id": 3,
"start": "2025-08-12T22:00:00Z",
"end": "2025-08-13T22:00:00Z"
},
{
"id": 14,
"start": "2025-08-15T22:00:00Z",
"end": "2025-08-17T22:00:00Z"
}
]
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param item: The ``id`` field of the item to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event/item does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/items/(item)/program_times/(id)/
Returns information on one program time, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/items/1/program_times/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,
"start": "2025-08-15T22:00:00Z",
"end": "2025-10-27T23:00:00Z"
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param item: The ``id`` field of the item to fetch
:param id: The ``id`` field of the program time 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)/items/(item)/program_times/
Creates a new program time
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/items/1/program_times/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
{
"start": "2025-08-15T10:00:00Z",
"end": "2025-08-15T22:00:00Z"
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"id": 17,
"start": "2025-08-15T10:00:00Z",
"end": "2025-08-15T22:00:00Z"
}
:param organizer: The ``slug`` field of the organizer of the event/item to create a program time for
:param event: The ``slug`` field of the event to create a program time for
:param item: The ``id`` field of the item to create a program time for
:statuscode 201: no error
:statuscode 400: The program time 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)/items/(item)/program_times/(id)/
Update a program time. 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/items/1/program_times/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 94
{
"start": "2025-08-14T10:00:00Z"
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"start": "2025-08-14T10:00:00Z",
"end": "2025-08-15T12:00:00Z"
}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the item to modify
:param id: The ``id`` field of the program time to modify
:statuscode 200: no error
:statuscode 400: The program time 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)/items/(id)/program_times/(id)/
Delete a program time.
**Example request**:
.. sourcecode:: http
DELETE /api/v1/organizers/bigevents/events/sampleconf/items/1/program_times/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 item to modify
:param id: The ``id`` field of the program time 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.

View File

@@ -139,10 +139,6 @@ has_variations boolean Shows whether
variations list of objects A list with one object for each variation of this item.
Can be empty. Only writable during creation,
use separate endpoint to modify this later.
program_times list of objects A list with one object for each program time of this item.
Can be empty. Only writable during creation,
use separate endpoint to modify this later.
Not available for items in event series.
├ id integer Internal ID of the variation
├ value multi-lingual string The "name" of the variation
├ default_price money (string) The price set directly for this variation or ``null``
@@ -229,10 +225,6 @@ meta_data object Values set fo
The ``hidden_if_item_available_mode`` attributes has been added.
.. versionchanged:: 2025.9
The ``program_times`` attribute has been added.
Notes
-----
@@ -240,11 +232,9 @@ Please note that an item either always has variations or never has. Once created
change to an item without and vice versa. To create an item with variations ensure that you POST an item with at least
one variation.
Also note that ``variations``, ``bundles``, ``addons`` and ``program_times`` are only supported on ``POST``. To update/delete variations,
bundles, add-ons and program times please use the dedicated nested endpoints. By design this endpoint does not support ``PATCH`` and ``PUT``
with nested ``variations``, ``bundles``, ``addons`` and/or ``program_times``.
``program_times`` is not available to items in event series.
Also note that ``variations``, ``bundles``, and ``addons`` are only supported on ``POST``. To update/delete variations,
bundles, and add-ons please use the dedicated nested endpoints. By design this endpoint does not support ``PATCH`` and ``PUT``
with nested ``variations``, ``bundles`` and/or ``addons``.
Endpoints
---------
@@ -383,8 +373,7 @@ Endpoints
}
],
"addons": [],
"bundles": [],
"program_times": []
"bundles": []
}
]
}
@@ -536,8 +525,7 @@ Endpoints
}
],
"addons": [],
"bundles": [],
"program_times": []
"bundles": []
}
:param organizer: The ``slug`` field of the organizer to fetch
@@ -665,13 +653,7 @@ Endpoints
}
],
"addons": [],
"bundles": [],
"program_times": [
{
"start": "2025-08-14T22:00:00Z",
"end": "2025-08-15T00:00:00Z"
}
]
"bundles": []
}
**Example response**:
@@ -791,13 +773,7 @@ Endpoints
}
],
"addons": [],
"bundles": [],
"program_times": [
{
"start": "2025-08-14T22:00:00Z",
"end": "2025-08-15T00:00:00Z"
}
]
"bundles": []
}
:param organizer: The ``slug`` field of the organizer of the event to create an item for
@@ -813,9 +789,8 @@ Endpoints
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 ``has_variations``, ``variations``, ``addon`` and the
``program_times`` field. If you need to update/delete variations, add-ons or program times, please use the nested
dedicated endpoints.
You can change all fields of the resource except the ``has_variations``, ``variations`` and the ``addon`` field. If
you need to update/delete variations or add-ons please use the nested dedicated endpoints.
**Example request**:
@@ -949,8 +924,7 @@ Endpoints
}
],
"addons": [],
"bundles": [],
"program_times": []
"bundles": []
}
:param organizer: The ``slug`` field of the organizer to modify

View File

@@ -41,7 +41,6 @@ expires datetime The order will
payment_date date **DEPRECATED AND INACCURATE** Date of payment receipt
payment_provider string **DEPRECATED AND INACCURATE** Payment provider used for this order
total money (string) Total value of this order
tax_rounding_mode string Tax rounding mode, see :ref:`algorithms-rounding`
comment string Internal comment on this order
api_meta object Meta data for that order. Only available through API, no guarantees
on the content structure. You can use this to save references to your system.
@@ -66,16 +65,11 @@ invoice_address object Invoice address
├ state string Customer state (ISO 3166-2 code). Only supported in
AU, BR, CA, CN, MY, MX, and US.
├ internal_reference string Customer's internal reference to be printed on the invoice
├ custom_field string Custom invoice address field
├ vat_id string Customer VAT ID
vat_id_validated string ``true``, if the VAT ID has been validated against the
vat_id_validated string ``true``, if the VAT ID has been validated against the
EU VAT service and validation was successful. This only
happens in rare cases.
├ transmission_type string Transmission channel for invoice (see also :ref:`rest-transmission-types`).
Defaults to ``email``.
└ transmission_info object Transmission-channel specific information (or ``null``).
See also :ref:`rest-transmission-types`.
positions list of objects List of order positions (see below). By default, only
non-canceled positions are included.
fees list of objects List of fees included in the order total. By default, only
@@ -148,14 +142,6 @@ plugin_data object Additional data
The ``plugin_data`` attribute has been added.
.. versionchanged:: 2025.6
The ``invoice_address.transmission_type`` and ``invoice_address.transmission_info`` attributes have been added.
.. versionchanged:: 2025.10
The ``tax_rounding_mode`` attribute has been added.
.. _order-position-resource:
Order position resource
@@ -363,7 +349,6 @@ List of all orders
"payment_provider": "banktransfer",
"fees": [],
"total": "23.00",
"tax_rounding_mode": "line",
"comment": "",
"custom_followup_at": null,
"checkin_attention": false,
@@ -383,9 +368,7 @@ List of all orders
"state": "",
"internal_reference": "",
"vat_id": "EU123456789",
"vat_id_validated": false,
"transmission_type": "email",
"transmission_info": {}
"vat_id_validated": false
},
"positions": [
{
@@ -424,7 +407,6 @@ List of all orders
"seat": null,
"checkins": [
{
"id": 1337,
"list": 44,
"type": "entry",
"gate": null,
@@ -608,7 +590,6 @@ Fetching individual orders
"payment_provider": "banktransfer",
"fees": [],
"total": "23.00",
"tax_rounding_mode": "line",
"comment": "",
"api_meta": {},
"custom_followup_at": null,
@@ -629,9 +610,7 @@ Fetching individual orders
"state": "",
"internal_reference": "",
"vat_id": "EU123456789",
"vat_id_validated": false,
"transmission_type": "email",
"transmission_info": {}
"vat_id_validated": false
},
"positions": [
{
@@ -670,7 +649,6 @@ Fetching individual orders
"seat": null,
"checkins": [
{
"id": 1337,
"list": 44,
"type": "entry",
"gate": null,
@@ -1018,7 +996,6 @@ Creating orders
provider will not be called to do anything about this (i.e. if you pass a bank account to a debit provider, *no*
charge will be created), this is just informative in case you *handled the payment already*.
* ``payment_date`` (optional) Date and time of the completion of the payment.
* ``tax_rounding_mode`` (optional)
* ``comment`` (optional)
* ``custom_followup_at`` (optional)
* ``checkin_attention`` (optional)
@@ -1038,10 +1015,8 @@ Creating orders
* ``internal_reference``
* ``vat_id``
* ``vat_id_validated`` (optional) If you need support for reverse charge (rarely the case), you need to check
yourself if the passed VAT ID is a valid EU VAT ID. In that case, set this to ``true``. Only valid VAT IDs will
trigger reverse charge taxation. Don't forget to set ``is_business`` as well!
* ``transmission_type`` (optional, defaults to ``email``)
* ``transmission_info`` (optional, see also :ref:`rest-transmission-types`)
yourself if the passed VAT ID is a valid EU VAT ID. In that case, set this to ``true``. Only valid VAT IDs will
trigger reverse charge taxation. Don't forget to set ``is_business`` as well!
* ``positions``
@@ -1066,7 +1041,6 @@ Creating orders
* ``valid_until`` (optional, if both ``valid_from`` and ``valid_until`` are **missing** (not ``null``) the availability will be computed from the given product)
* ``requested_valid_from`` (optional, can be set **instead** of ``valid_from`` and ``valid_until`` to signal a user choice for the start time that may or may not be respected)
* ``use_reusable_medium`` (optional, causes the new ticket to take over the given reusable medium, identified by its ID)
* ``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``
@@ -1643,7 +1617,6 @@ List of all order positions
"blocked": null,
"checkins": [
{
"id": 1337,
"list": 44,
"type": "entry",
"gate": null,
@@ -1772,7 +1745,6 @@ Fetching individual positions
"seat": null,
"checkins": [
{
"id": 1337,
"list": 44,
"type": "entry",
"gate": null,
@@ -2517,7 +2489,6 @@ Order payment endpoints
{
"amount": "23.00",
"comment": "Overpayment",
"mark_canceled": false
}

View File

@@ -60,9 +60,6 @@ The following values for ``action_types`` are valid with pretix core:
* ``pretix.event.added``
* ``pretix.event.changed``
* ``pretix.event.deleted``
* ``pretix.voucher.added``
* ``pretix.voucher.changed``
* ``pretix.voucher.deleted``
* ``pretix.subevent.added``
* ``pretix.subevent.changed``
* ``pretix.subevent.deleted``

View File

@@ -178,124 +178,3 @@ Flowchart
---------
.. image:: /images/cart_pricing.png
.. _`algorithms-rounding`:
Rounding of taxes
-----------------
pretix internally always stores taxes on a per-line level, like this:
========== ========== =========== ======= =============
Product Tax rate Net price Tax Gross price
========== ========== =========== ======= =============
Ticket A 19 % 84.03 15.97 100.00
Ticket B 19 % 84.03 15.97 100.00
Ticket C 19 % 84.03 15.97 100.00
Ticket D 19 % 84.03 15.97 100.00
Ticket E 19 % 84.03 15.97 100.00
Sum 420.15 79.85 500.00
========== ========== =========== ======= =============
Whether the net price is computed from the gross price or vice versa is configured on the tax rule and may differ for every line.
The line-based computation has a few significant advantages:
- We can report both net and gross prices for every individual ticket.
- We can report both net and gross prices for every filter imaginable, such as the gross sum of all sales of Ticket A
or the net sum of all sales for a specific date in an event series. All numbers will be exact.
- When splitting the order into two, both net price and gross price are split without any changes in rounding.
The main disadvantage is that the tax looks "wrong" when computed from the sum. Taking the sum of net prices (420.15)
and multiplying it with the tax rate (19%) yields a tax amount of 79.83 (instead of 79.85) and a gross sum of 499.98
(instead of 499.98). This becomes a problem when juristictions, data formats, or external systems expect this calculation
to work on the level of the entire order. A prominent example is the EN 16931 standard for e-invoicing that
does not allow the computation as created by pretix.
However, calculating the tax rate from the net total has significant disadvantages:
- It is impossible to guarantee a stable gross price this way, i.e. if you advertise a price of €100 per ticket to
consumers, they will be confused when they only need to pay €499.98 for 5 tickets.
- Some prices are impossible, e.g. you cannot sell a ticket for a gross price of €99.99 at a 19% tax rate, since there
is no two-decimal net price that would be computed to a gross price of €99.99.
- When splitting an order into two, the combined of the new orders is not guaranteed to be the same as the total of the
original order. Therefore, additional payments or refunds of very small amounts might be necessary.
To allow organizers to make their own choices on this matter, pretix provides the following options:
Compute taxes for every line individually
"""""""""""""""""""""""""""""""""""""""""
Algorithm identifier: ``line``
This is our original algorithm where the tax value is rounded for every line individually.
**This is our current default algorithm and we recommend it whenever you do not have different requirements** (see below).
For the example above:
========== ========== =========== ======= =============
Product Tax rate Net price Tax Gross price
========== ========== =========== ======= =============
Ticket A 19 % 84.03 15.97 100.00
Ticket B 19 % 84.03 15.97 100.00
Ticket C 19 % 84.03 15.97 100.00
Ticket D 19 % 84.03 15.97 100.00
Ticket E 19 % 84.03 15.97 100.00
Sum 420.15 79.85 500.00
========== ========== =========== ======= =============
Compute taxes based on net total
""""""""""""""""""""""""""""""""
Algorithm identifier: ``sum_by_net``
In this algorithm, the tax value and gross total are computed from the sum of the net prices. To accomplish this within
our data model, the gross price and tax of some of the tickets will be changed by the minimum currency unit (e.g. €0.01).
The net price of the tickets always stay the same.
**This is the algorithm intended by EN 16931 invoices and our recommendation to use for e-invoicing when (primarily) business customers are involved.**
The main downside is that it might be confusing when selling to consumers, since the amounts to be paid change in unexpected ways.
For the example above, the customer expects to pay 5 times 100.00, but they are are in fact charged 499.98:
========== ========== =========== ============================== ==============================
Product Tax rate Net price Tax Gross price
========== ========== =========== ============================== ==============================
Ticket A 19 % 84.03 15.96 (incl. -0.01 rounding) 99.99 (incl. -0.01 rounding)
Ticket B 19 % 84.03 15.96 (incl. -0.01 rounding) 99.99 (incl. -0.01 rounding)
Ticket C 19 % 84.03 15.97 100.00
Ticket D 19 % 84.03 15.97 100.00
Ticket E 19 % 84.03 15.97 100.00
Sum 420.15 78.83 499.98
========== ========== =========== ============================== ==============================
Compute taxes based on net total with stable gross prices
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Algorithm identifier: ``sum_by_net_keep_gross``
In this algorithm, the tax value and gross total are computed from the sum of the net prices. However, the net prices
of some of the tickets will be changed automatically by the minimum currency unit (e.g. €0.01) such that the resulting
gross prices stay the same.
**This is less confusing to consumers and the end result is still compliant to EN 16931, so we recommend this for e-invoicing when (primarily) consumers are involved.**
The main downside is that it might be confusing when selling to business customers, since the prices of the identical tickets appear to be different.
Full computation for the example above:
========== ========== ============================= ============================== =============
Product Tax rate Net price Tax Gross price
========== ========== ============================= ============================== =============
Ticket A 19 % 84.04 (incl. 0.01 rounding) 15.96 (incl. -0.01 rounding) 100.00
Ticket B 19 % 84.04 (incl. 0.01 rounding) 15.96 (incl. -0.01 rounding) 100.00
Ticket C 19 % 84.03 15.97 100.00
Ticket D 19 % 84.03 15.97 100.00
Ticket E 19 % 84.03 15.97 100.00
Sum 420.17 79.83 500.00
========== ========== ============================= ============================== =============

View File

@@ -23,7 +23,7 @@ There are multiple signals that will be sent out in the ordering cycle:
.. automodule:: pretix.base.signals
:no-index:
:members: validate_cart, validate_cart_addons, validate_order, order_valid_if_pending, order_fee_calculation, order_paid, order_placed, order_canceled, order_reactivated, order_expired, order_expiry_changed, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download, order_split, order_gracefully_delete, build_invoice_data, invoice_line_text
:members: validate_cart, validate_cart_addons, validate_order, order_valid_if_pending, order_fee_calculation, order_paid, order_placed, order_canceled, order_reactivated, order_expired, order_expiry_changed, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download, order_split, order_gracefully_delete, invoice_line_text
Check-ins
"""""""""
@@ -37,7 +37,7 @@ Frontend
--------
.. automodule:: pretix.presale.signals
:members: html_head, html_footer, footer_link, global_footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header, seatingframe_html_head, filter_subevents
:members: html_head, html_footer, footer_link, global_footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header, seatingframe_html_head
.. automodule:: pretix.presale.signals

View File

@@ -13,7 +13,6 @@ Contents:
email
placeholder
invoice
invoicetransmission
shredder
import
customview

View File

@@ -1,65 +0,0 @@
.. highlight:: python
:linenothreshold: 5
Writing an invoice transmission plugin
======================================
An invoice transmission provider transports an invoice from the sender to the recipient.
There are pre-defined types of invoice transmission in pretix, currently ``"email"``, ``"peppol"``, and ``"it_sdi"``.
You can find more information about them at :ref:`rest-transmission-types`.
New transmission types can not be added by plugins but need to be added to pretix itself.
However, plugins can provide implementations for the actual transmission.
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
Output registration
-------------------
New invoice transmission providers can be registered through the :ref:`registry <registries>` mechanism
.. code-block:: python
from pretix.base.invoicing.transmission import transmission_providers, TransmissionProvider
@transmission_providers.new()
class SdiTransmissionProvider(TransmissionProvider):
identifier = "fatturapa_providerabc"
type = "it_sdi"
verbose_name = _("FatturaPA through provider ABC")
...
The provider class
------------------
.. class:: pretix.base.invoicing.transmission.TransmissionProvider
.. autoattribute:: identifier
This is an abstract attribute, you **must** override this!
.. autoattribute:: type
This is an abstract attribute, you **must** override this!
.. autoattribute:: verbose_name
This is an abstract attribute, you **must** override this!
.. autoattribute:: priority
.. autoattribute:: testmode_supported
.. automethod:: is_ready
This is an abstract method, you **must** override this!
.. automethod:: is_available
This is an abstract method, you **must** override this!
.. automethod:: transmit
This is an abstract method, you **must** override this!
.. automethod:: settings_url

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -23,7 +23,6 @@ partition "For every cart position" {
--> "Store as line_price (gross), tax_rate"
}
--> "Apply discount engine"
--> "Apply tax rounding"
--> "Store as price (gross)"
@enduml

View File

@@ -6,4 +6,4 @@ sphinxcontrib-images
sphinxcontrib-jquery
sphinxcontrib-spelling==8.*
sphinxemoji
pyenchant==3.3.*
pyenchant==3.2.*

View File

@@ -7,4 +7,4 @@ sphinxcontrib-images
sphinxcontrib-jquery
sphinxcontrib-spelling==8.*
sphinxemoji
pyenchant==3.3.*
pyenchant==3.2.*

View File

@@ -28,24 +28,23 @@ classifiers = [
dependencies = [
"arabic-reshaper==3.0.0", # Support for Arabic in reportlab
"babel",
"BeautifulSoup4==4.14.*",
"BeautifulSoup4==4.13.*",
"bleach==6.2.*",
"celery==5.5.*",
"chardet==5.2.*",
"cryptography>=44.0.0",
"css-inline==0.18.*",
"css-inline==0.17.*",
"defusedcsv>=1.1.0",
"dnspython==2.*",
"Django[argon2]==4.2.*,>=4.2.26",
"Django[argon2]==4.2.*,>=4.2.15",
"django-bootstrap3==25.2",
"django-compressor==4.5.1",
"django-countries==7.6.*",
"django-filter==25.1",
"django-formset-js-improved==0.5.0.4",
"django-formset-js-improved==0.5.0.3",
"django-formtools==2.5.1",
"django-hierarkey==2.0.*,>=2.0.1",
"django-hierarkey==2.0.*",
"django-hijack==3.7.*",
"django-i18nfield==1.11.*",
"django-i18nfield==1.10.*",
"django-libsass==0.9",
"django-localflavor==5.0",
"django-markup",
@@ -65,7 +64,7 @@ dependencies = [
"kombu==5.5.*",
"libsass==0.23.*",
"lxml",
"markdown==3.9", # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3.
"markdown==3.8.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
"mt-940==4.30.*",
"oauthlib==3.3.*",
@@ -77,12 +76,12 @@ dependencies = [
"phonenumberslite==9.0.*",
"Pillow==11.3.*",
"pretix-plugin-build",
"protobuf==6.33.*",
"protobuf==6.32.*",
"psycopg2-binary",
"pycountry",
"pycparser==2.23",
"pycparser==2.22",
"pycryptodome==3.23.*",
"pypdf==6.4.*",
"pypdf==6.0.*",
"python-bidi==0.6.*", # Support for Arabic in reportlab
"python-dateutil==2.9.*",
"pytz",
@@ -91,9 +90,9 @@ dependencies = [
"qrcode==8.2",
"redis==6.4.*",
"reportlab==4.4.*",
"requests==2.32.*",
"sentry-sdk==2.46.*",
"sepaxml==2.7.*",
"requests==2.31.*",
"sentry-sdk==2.35.*",
"sepaxml==2.6.*",
"stripe==7.9.*",
"text-unidecode==1.*",
"tlds>=2020041600",
@@ -101,27 +100,27 @@ dependencies = [
"ua-parser==1.0.*",
"vat_moss_forked==2020.3.20.0.11.0",
"vobject==0.9.*",
"webauthn==2.7.*",
"webauthn==2.6.*",
"zeep==4.3.*"
]
[project.optional-dependencies]
memcached = ["pylibmc"]
dev = [
"aiohttp==3.13.*",
"aiohttp==3.12.*",
"coverage",
"coveralls",
"fakeredis==2.32.*",
"fakeredis==2.31.*",
"flake8==7.3.*",
"freezegun",
"isort==6.1.*",
"isort==6.0.*",
"pep8-naming==0.15.*",
"potypo",
"pytest-asyncio>=0.24",
"pytest-cache",
"pytest-cov",
"pytest-django==4.*",
"pytest-mock==3.15.*",
"pytest-mock==3.14.*",
"pytest-sugar",
"pytest-xdist==3.8.*",
"pytest==8.4.*",

View File

@@ -25,8 +25,8 @@ coverage:
coverage run -m py.test
npminstall:
# keep this in sync with pretix/_build.py!
# keep this in sync with setup.py!
mkdir -p pretix/static.dist/node_prefix/
cp -r pretix/static/npm_dir/* pretix/static.dist/node_prefix/
npm ci --prefix=pretix/static.dist/node_prefix
npm install --prefix=pretix/static.dist/node_prefix

View File

@@ -2,8 +2,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -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__ = "2025.11.0.dev0"
__version__ = "2025.7.0.dev0"

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -39,7 +39,7 @@ def npm_install():
node_prefix = os.path.join(here, 'static.dist', 'node_prefix')
os.makedirs(node_prefix, exist_ok=True)
shutil.copytree(os.path.join(here, 'static', 'npm_dir'), node_prefix, dirs_exist_ok=True)
subprocess.check_call('npm ci', shell=True, cwd=node_prefix)
subprocess.check_call('npm install', shell=True, cwd=node_prefix)
npm_installed = True

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,23 +0,0 @@
# Generated by Django 4.2.24 on 2025-11-14 16:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("pretixapi", "0013_alter_webhookcallretry_retry_not_before"),
]
operations = [
migrations.AlterField(
model_name="webhook",
name="target_url",
field=models.URLField(max_length=1024),
),
migrations.AlterField(
model_name="webhookcall",
name="target_url",
field=models.URLField(max_length=1024),
),
]

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -114,7 +114,7 @@ class OAuthRefreshToken(AbstractRefreshToken):
class WebHook(models.Model):
organizer = models.ForeignKey('pretixbase.Organizer', on_delete=models.CASCADE, related_name='webhooks')
enabled = models.BooleanField(default=True, verbose_name=_("Enable webhook"))
target_url = models.URLField(verbose_name=_("Target URL"), max_length=1024)
target_url = models.URLField(verbose_name=_("Target URL"), max_length=255)
all_events = models.BooleanField(default=True, verbose_name=_("All events (including newly created ones)"))
limit_events = models.ManyToManyField('pretixbase.Event', verbose_name=_("Limit to events"), blank=True)
comment = models.CharField(verbose_name=_("Comment"), max_length=255, null=True, blank=True)
@@ -140,7 +140,7 @@ class WebHookEventListener(models.Model):
class WebHookCall(models.Model):
webhook = models.ForeignKey('WebHook', on_delete=models.CASCADE, related_name='calls')
datetime = models.DateTimeField(auto_now_add=True)
target_url = models.URLField(max_length=1024)
target_url = models.URLField(max_length=255)
action_type = models.CharField(max_length=255)
is_retry = models.BooleanField(default=False)
execution_time = models.FloatField(null=True)

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -805,7 +805,6 @@ class EventSettingsSerializer(SettingsSerializer):
'invoice_reissue_after_modify',
'invoice_include_free',
'invoice_generate',
'invoice_period',
'invoice_numbers_consecutive',
'invoice_numbers_prefix',
'invoice_numbers_prefix_cancellations',
@@ -820,7 +819,6 @@ class EventSettingsSerializer(SettingsSerializer):
'invoice_address_from',
'invoice_address_from_zipcode',
'invoice_address_from_city',
'invoice_address_from_state',
'invoice_address_from_country',
'invoice_address_from_tax_id',
'invoice_address_from_vat_id',
@@ -830,7 +828,6 @@ class EventSettingsSerializer(SettingsSerializer):
'invoice_eu_currencies',
'invoice_logo_image',
'invoice_renderer_highlight_order_code',
'tax_rounding',
'cancel_allow_user',
'cancel_allow_user_until',
'cancel_allow_user_unpaid_keep',
@@ -953,7 +950,6 @@ class DeviceEventSettingsSerializer(EventSettingsSerializer):
'invoice_address_from',
'invoice_address_from_zipcode',
'invoice_address_from_city',
'invoice_address_from_state',
'invoice_address_from_country',
'invoice_address_from_tax_id',
'invoice_address_from_vat_id',

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -19,16 +19,45 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django import forms
from django.conf import settings
from django.http import QueryDict
from pytz import common_timezones
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from pretix.api.serializers.forms import form_field_to_serializer_field
from pretix.base.exporter import OrganizerLevelExportMixin
from pretix.base.models import ScheduledEventExport, ScheduledOrganizerExport
from pretix.base.timeframes import SerializerDateFrameField
from pretix.base.timeframes import DateFrameField, SerializerDateFrameField
class FormFieldWrapperField(serializers.Field):
def __init__(self, *args, **kwargs):
self.form_field = kwargs.pop('form_field')
super().__init__(*args, **kwargs)
def to_representation(self, value):
return self.form_field.widget.format_value(value)
def to_internal_value(self, data):
d = self.form_field.widget.value_from_datadict({'name': data}, {}, 'name')
d = self.form_field.clean(d)
return d
simple_mappings = (
(forms.DateField, serializers.DateField, ()),
(forms.TimeField, serializers.TimeField, ()),
(forms.SplitDateTimeField, serializers.DateTimeField, ()),
(forms.DateTimeField, serializers.DateTimeField, ()),
(forms.DecimalField, serializers.DecimalField, ('max_digits', 'decimal_places', 'min_value', 'max_value')),
(forms.FloatField, serializers.FloatField, ()),
(forms.IntegerField, serializers.IntegerField, ()),
(forms.EmailField, serializers.EmailField, ()),
(forms.UUIDField, serializers.UUIDField, ()),
(forms.URLField, serializers.URLField, ()),
(forms.BooleanField, serializers.BooleanField, ()),
)
class SerializerDescriptionField(serializers.Field):
@@ -52,6 +81,13 @@ class ExporterSerializer(serializers.Serializer):
input_parameters = SerializerDescriptionField(source='_serializer')
class PrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
if isinstance(value, int):
return value
return super().to_representation(value)
class JobRunSerializer(serializers.Serializer):
def __init__(self, *args, **kwargs):
ex = kwargs.pop('exporter')
@@ -66,7 +102,59 @@ class JobRunSerializer(serializers.Serializer):
many=True
)
for k, v in ex.export_form_fields.items():
self.fields[k] = form_field_to_serializer_field(v)
for m_from, m_to, m_kwargs in simple_mappings:
if isinstance(v, m_from):
self.fields[k] = m_to(
required=v.required,
allow_null=not v.required,
validators=v.validators,
**{kwarg: getattr(v, kwargs, None) for kwarg in m_kwargs}
)
break
if isinstance(v, forms.NullBooleanField):
self.fields[k] = serializers.BooleanField(
required=v.required,
allow_null=True,
validators=v.validators,
)
if isinstance(v, forms.ModelMultipleChoiceField):
self.fields[k] = PrimaryKeyRelatedField(
queryset=v.queryset,
required=v.required,
allow_empty=not v.required,
validators=v.validators,
many=True
)
elif isinstance(v, forms.ModelChoiceField):
self.fields[k] = PrimaryKeyRelatedField(
queryset=v.queryset,
required=v.required,
allow_null=not v.required,
validators=v.validators,
)
elif isinstance(v, forms.MultipleChoiceField):
self.fields[k] = serializers.MultipleChoiceField(
choices=v.choices,
required=v.required,
allow_empty=not v.required,
validators=v.validators,
)
elif isinstance(v, forms.ChoiceField):
self.fields[k] = serializers.ChoiceField(
choices=v.choices,
required=v.required,
allow_null=not v.required,
validators=v.validators,
)
elif isinstance(v, DateFrameField):
self.fields[k] = SerializerDateFrameField(
required=v.required,
allow_null=not v.required,
validators=v.validators,
)
else:
self.fields[k] = FormFieldWrapperField(form_field=v, required=v.required, allow_null=not v.required)
def to_internal_value(self, data):
if isinstance(data, QueryDict):

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,115 +0,0 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django import forms
from rest_framework import serializers
from pretix.base.timeframes import DateFrameField, SerializerDateFrameField
simple_mappings = (
(forms.DateField, serializers.DateField, ()),
(forms.TimeField, serializers.TimeField, ()),
(forms.SplitDateTimeField, serializers.DateTimeField, ()),
(forms.DateTimeField, serializers.DateTimeField, ()),
(forms.DecimalField, serializers.DecimalField, ('max_digits', 'decimal_places', 'min_value', 'max_value')),
(forms.FloatField, serializers.FloatField, ()),
(forms.IntegerField, serializers.IntegerField, ()),
(forms.EmailField, serializers.EmailField, ()),
(forms.UUIDField, serializers.UUIDField, ()),
(forms.URLField, serializers.URLField, ()),
(forms.BooleanField, serializers.BooleanField, ()),
)
class PrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
if isinstance(value, int):
return value
return super().to_representation(value)
class FormFieldWrapperField(serializers.Field):
def __init__(self, *args, **kwargs):
self.form_field = kwargs.pop('form_field')
super().__init__(*args, **kwargs)
def to_representation(self, value):
return self.form_field.widget.format_value(value)
def to_internal_value(self, data):
d = self.form_field.widget.value_from_datadict({'name': data}, {}, 'name')
d = self.form_field.clean(d)
return d
def form_field_to_serializer_field(field):
for m_from, m_to, m_kwargs in simple_mappings:
if isinstance(field, m_from):
return m_to(
required=field.required,
allow_null=not field.required,
validators=field.validators,
**{kwarg: getattr(field, kwarg, None) for kwarg in m_kwargs}
)
if isinstance(field, forms.NullBooleanField):
return serializers.BooleanField(
required=field.required,
allow_null=True,
validators=field.validators,
)
if isinstance(field, forms.ModelMultipleChoiceField):
return PrimaryKeyRelatedField(
queryset=field.queryset,
required=field.required,
allow_empty=not field.required,
validators=field.validators,
many=True
)
elif isinstance(field, forms.ModelChoiceField):
return PrimaryKeyRelatedField(
queryset=field.queryset,
required=field.required,
allow_null=not field.required,
validators=field.validators,
)
elif isinstance(field, forms.MultipleChoiceField):
return serializers.MultipleChoiceField(
choices=field.choices,
required=field.required,
allow_empty=not field.required,
validators=field.validators,
)
elif isinstance(field, forms.ChoiceField):
return serializers.ChoiceField(
choices=field.choices,
required=field.required,
allow_null=not field.required,
validators=field.validators,
)
elif isinstance(field, DateFrameField):
return SerializerDateFrameField(
required=field.required,
allow_null=not field.required,
validators=field.validators,
)
else:
return FormFieldWrapperField(form_field=field, required=field.required, allow_null=not field.required)

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -47,9 +47,8 @@ from pretix.api.serializers.event import MetaDataField
from pretix.api.serializers.fields import UploadedFileField
from pretix.api.serializers.i18n import I18nAwareModelSerializer
from pretix.base.models import (
Item, ItemAddOn, ItemBundle, ItemCategory, ItemMetaValue, ItemProgramTime,
ItemVariation, ItemVariationMetaValue, Question, QuestionOption, Quota,
SalesChannel,
Item, ItemAddOn, ItemBundle, ItemCategory, ItemMetaValue, ItemVariation,
ItemVariationMetaValue, Question, QuestionOption, Quota, SalesChannel,
)
@@ -188,12 +187,6 @@ class InlineItemAddOnSerializer(serializers.ModelSerializer):
'position', 'price_included', 'multi_allowed')
class InlineItemProgramTimeSerializer(serializers.ModelSerializer):
class Meta:
model = ItemProgramTime
fields = ('start', 'end')
class ItemBundleSerializer(serializers.ModelSerializer):
class Meta:
model = ItemBundle
@@ -219,37 +212,6 @@ class ItemBundleSerializer(serializers.ModelSerializer):
return data
class ItemProgramTimeSerializer(serializers.ModelSerializer):
class Meta:
model = ItemProgramTime
fields = ('id', 'start', 'end')
def validate(self, data):
data = super().validate(data)
full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {}
full_data.update(data)
start = full_data.get('start')
if not start:
raise ValidationError(_("The program start must not be empty."))
end = full_data.get('end')
if not end:
raise ValidationError(_("The program end must not be empty."))
if start > end:
raise ValidationError(_("The program end must not be before the program start."))
event = self.context['event']
if event.has_subevents:
raise ValidationError({
_("You cannot use program times on an event series.")
})
return data
class ItemAddOnSerializer(serializers.ModelSerializer):
class Meta:
model = ItemAddOn
@@ -288,7 +250,6 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
addons = InlineItemAddOnSerializer(many=True, required=False)
bundles = InlineItemBundleSerializer(many=True, required=False)
variations = InlineItemVariationSerializer(many=True, required=False)
program_times = InlineItemProgramTimeSerializer(many=True, required=False)
tax_rate = ItemTaxRateField(source='*', read_only=True)
meta_data = MetaDataField(required=False, source='*')
picture = UploadedFileField(required=False, allow_null=True, allowed_types=(
@@ -310,7 +271,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
'available_from', 'available_from_mode', 'available_until', 'available_until_mode',
'require_voucher', 'hide_without_voucher', 'allow_cancel', 'require_bundling',
'min_per_order', 'max_per_order', 'checkin_attention', 'checkin_text', 'has_variations', 'variations',
'addons', 'bundles', 'program_times', 'original_price', 'require_approval', 'generate_tickets',
'addons', 'bundles', 'original_price', 'require_approval', 'generate_tickets',
'show_quota_left', 'hidden_if_available', 'hidden_if_item_available', 'hidden_if_item_available_mode', 'allow_waitinglist',
'issue_giftcard', 'meta_data',
'require_membership', 'require_membership_types', 'require_membership_hidden', 'grant_membership_type',
@@ -333,9 +294,9 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
def validate(self, data):
data = super().validate(data)
if self.instance and ('addons' in data or 'variations' in data or 'bundles' in data or 'program_times' in data):
raise ValidationError(_('Updating add-ons, bundles, program times or variations via PATCH/PUT is not '
'supported. Please use the dedicated nested endpoint.'))
if self.instance and ('addons' in data or 'variations' in data or 'bundles' in data):
raise ValidationError(_('Updating add-ons, bundles, or variations via PATCH/PUT is not supported. Please use the '
'dedicated nested endpoint.'))
Item.clean_per_order(data.get('min_per_order'), data.get('max_per_order'))
Item.clean_available(data.get('available_from'), data.get('available_until'))
@@ -386,13 +347,6 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
ItemAddOn.clean_max_min_count(addon_data.get('max_count', 0), addon_data.get('min_count', 0))
return value
def validate_program_times(self, value):
if not self.instance:
for program_time_data in value:
ItemProgramTime.clean_start_end(self, start=program_time_data.get('start', None),
end=program_time_data.get('end', None))
return value
@cached_property
def item_meta_properties(self):
return {
@@ -410,7 +364,6 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
variations_data = validated_data.pop('variations') if 'variations' in validated_data else {}
addons_data = validated_data.pop('addons') if 'addons' in validated_data else {}
bundles_data = validated_data.pop('bundles') if 'bundles' in validated_data else {}
program_times_data = validated_data.pop('program_times') if 'program_times' in validated_data else {}
meta_data = validated_data.pop('meta_data', None)
picture = validated_data.pop('picture', None)
require_membership_types = validated_data.pop('require_membership_types', [])
@@ -445,8 +398,6 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
ItemAddOn.objects.create(base_item=item, **addon_data)
for bundle_data in bundles_data:
ItemBundle.objects.create(base_item=item, **bundle_data)
for program_time_data in program_times_data:
ItemProgramTime.objects.create(item=item, **program_time_data)
# Meta data
if meta_data is not None:
@@ -599,7 +550,7 @@ class QuestionSerializer(I18nAwareModelSerializer):
if full_data.get('show_during_checkin') and full_data.get('type') in Question.SHOW_DURING_CHECKIN_UNSUPPORTED:
raise ValidationError(_('This type of question cannot be shown during check-in.'))
Question.clean_items(event, full_data.get('items') or [])
Question.clean_items(event, full_data.get('items'))
return data
def validate_options(self, value):
@@ -615,7 +566,7 @@ class QuestionSerializer(I18nAwareModelSerializer):
@transaction.atomic
def create(self, validated_data):
options_data = validated_data.pop('options') if 'options' in validated_data else []
items = validated_data.pop('items', [])
items = validated_data.pop('items')
question = Question.objects.create(**validated_data)
question.items.set(items)

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -42,7 +42,6 @@ from rest_framework.reverse import reverse
from pretix.api.serializers import CompatibleJSONField
from pretix.api.serializers.event import SubEventSerializer
from pretix.api.serializers.forms import form_field_to_serializer_field
from pretix.api.serializers.i18n import I18nAwareModelSerializer
from pretix.api.serializers.item import (
InlineItemVariationSerializer, ItemSerializer, QuestionSerializer,
@@ -50,12 +49,10 @@ from pretix.api.serializers.item import (
from pretix.api.signals import order_api_details, orderposition_api_details
from pretix.base.decimal import round_decimal
from pretix.base.i18n import language
from pretix.base.invoicing.transmission import get_transmission_types
from pretix.base.models import (
CachedFile, Checkin, Customer, Device, Invoice, InvoiceAddress,
InvoiceLine, Item, ItemVariation, Order, OrderPosition, Question,
QuestionAnswer, ReusableMedium, SalesChannel, Seat, SubEvent, TaxRule,
Voucher,
CachedFile, Checkin, Customer, Invoice, InvoiceAddress, InvoiceLine, Item,
ItemVariation, Order, OrderPosition, Question, QuestionAnswer,
ReusableMedium, SalesChannel, Seat, SubEvent, TaxRule, Voucher,
)
from pretix.base.models.orders import (
BlockedTicketSecret, CartPosition, OrderFee, OrderPayment, OrderRefund,
@@ -65,13 +62,10 @@ from pretix.base.pdf import get_images, get_variables
from pretix.base.services.cart import error_messages
from pretix.base.services.locking import LOCK_TRUST_WINDOW, lock_objects
from pretix.base.services.pricing import (
apply_discounts, apply_rounding, get_line_price, get_listed_price,
is_included_for_free,
apply_discounts, get_line_price, get_listed_price, is_included_for_free,
)
from pretix.base.services.quotas import QuotaAvailability
from pretix.base.settings import (
COUNTRIES_WITH_STATE_IN_ADDRESS, ROUNDING_MODES,
)
from pretix.base.settings import COUNTRIES_WITH_STATE_IN_ADDRESS
from pretix.base.signals import register_ticket_outputs
from pretix.helpers.countries import CachedCountries
from pretix.multidomain.urlreverse import build_absolute_uri
@@ -108,13 +102,6 @@ class CountryField(serializers.Field):
return str(src) if src else None
class TransmissionInfoSerializer(serializers.Serializer):
def __init__(self, *args, transmission_type, **kwargs):
super().__init__(*args, **kwargs)
for k, v in transmission_type.invoice_address_form_fields.items():
self.fields[k] = form_field_to_serializer_field(v)
class InvoiceAddressSerializer(I18nAwareModelSerializer):
country = CompatibleCountryField(source='*')
name = serializers.CharField(required=False)
@@ -122,8 +109,7 @@ class InvoiceAddressSerializer(I18nAwareModelSerializer):
class Meta:
model = InvoiceAddress
fields = ('last_modified', 'is_business', 'company', 'name', 'name_parts', 'street', 'zipcode', 'city', 'country',
'state', 'vat_id', 'vat_id_validated', 'custom_field', 'internal_reference', 'transmission_type',
'transmission_info')
'state', 'vat_id', 'vat_id_validated', 'custom_field', 'internal_reference')
read_only_fields = ('last_modified',)
def __init__(self, *args, **kwargs):
@@ -161,48 +147,6 @@ class InvoiceAddressSerializer(I18nAwareModelSerializer):
{'state': ['"{}" is not a known subdivision of the country "{}".'.format(data.get('state'), cc)]}
)
if data.get("transmission_type"):
for t in get_transmission_types():
if data.get("transmission_type") == t.identifier:
if not t.is_available(self.context["request"].event, data.get("country"), data.get("is_business")):
raise ValidationError({
"transmission_type": "The selected transmission type is not available for this country or address type."
})
ts = TransmissionInfoSerializer(transmission_type=t, data=data.get("transmission_info", {}))
try:
ts.is_valid(raise_exception=True)
except ValidationError as e:
raise ValidationError(
{"transmission_info": e.detail}
)
data["transmission_info"] = ts.validated_data
required_fields = t.invoice_address_form_fields_required(data.get("country"), data.get("is_business"))
for r in required_fields:
if r in self.fields:
if not data.get(r):
raise ValidationError(
{r: "This field is required for the selected type of invoice transmission."}
)
else:
if not ts.validated_data.get(r):
raise ValidationError(
{"transmission_info": {r: "This field is required for the selected type of invoice transmission."}}
)
break # do not call else branch of for loop
elif t.exclusive:
if t.is_available(self.context["request"].event, data.get("country"), data.get("is_business")):
raise ValidationError({
"transmission_type": "The transmission type '%s' must be used for this country or address type." % (
t.identifier,
)
})
else:
raise ValidationError(
{"transmission_type": "Unknown transmission type."}
)
return data
@@ -329,18 +273,6 @@ class AnswerSerializer(I18nAwareModelSerializer):
return data
class InlineCheckinSerializer(I18nAwareModelSerializer):
device_id = serializers.SlugRelatedField(
source='device',
slug_field='device_id',
read_only=True,
)
class Meta:
model = Checkin
fields = ('id', 'datetime', 'list', 'auto_checked_in', 'gate', 'device', 'device_id', 'type')
class CheckinSerializer(I18nAwareModelSerializer):
device_id = serializers.SlugRelatedField(
source='device',
@@ -350,10 +282,7 @@ class CheckinSerializer(I18nAwareModelSerializer):
class Meta:
model = Checkin
fields = (
'id', 'successful', 'error_reason', 'error_explanation', 'position', 'datetime', 'list', 'created',
'auto_checked_in', 'gate', 'device', 'device_id', 'type'
)
fields = ('id', 'datetime', 'list', 'auto_checked_in', 'gate', 'device', 'device_id', 'type')
class PrintLogSerializer(serializers.ModelSerializer):
@@ -579,7 +508,7 @@ class OrderPositionPluginDataField(serializers.Field):
class OrderPositionSerializer(I18nAwareModelSerializer):
checkins = InlineCheckinSerializer(many=True, read_only=True)
checkins = CheckinSerializer(many=True, read_only=True)
print_logs = PrintLogSerializer(many=True, read_only=True)
answers = AnswerSerializer(many=True)
downloads = PositionDownloadsField(source='*', read_only=True)
@@ -852,15 +781,14 @@ class OrderSerializer(I18nAwareModelSerializer):
list_serializer_class = OrderListSerializer
fields = (
'code', 'event', 'status', 'testmode', 'secret', 'email', 'phone', 'locale', 'datetime', 'expires', 'payment_date',
'payment_provider', 'fees', 'total', 'tax_rounding_mode', 'comment', 'custom_followup_at', 'invoice_address',
'positions', 'downloads', 'checkin_attention', 'checkin_text', 'last_modified', 'payments', 'refunds',
'require_approval', 'sales_channel', 'url', 'customer', 'valid_if_pending', 'api_meta', 'cancellation_date',
'plugin_data',
'payment_provider', 'fees', 'total', 'comment', 'custom_followup_at', 'invoice_address', 'positions', 'downloads',
'checkin_attention', 'checkin_text', 'last_modified', 'payments', 'refunds', 'require_approval', 'sales_channel',
'url', 'customer', 'valid_if_pending', 'api_meta', 'cancellation_date', 'plugin_data',
)
read_only_fields = (
'code', 'status', 'testmode', 'secret', 'datetime', 'expires', 'payment_date',
'payment_provider', 'fees', 'total', 'tax_rounding_mode', 'positions', 'downloads', 'customer',
'last_modified', 'payments', 'refunds', 'require_approval', 'sales_channel', 'cancellation_date',
'payment_provider', 'fees', 'total', 'positions', 'downloads', 'customer',
'last_modified', 'payments', 'refunds', 'require_approval', 'sales_channel', 'cancellation_date'
)
def __init__(self, *args, **kwargs):
@@ -1025,7 +953,7 @@ class OrderPositionCreateSerializer(I18nAwareModelSerializer):
fields = ('positionid', 'item', 'variation', 'price', 'attendee_name', 'attendee_name_parts', 'attendee_email',
'company', 'street', 'zipcode', 'city', 'country', 'state', 'is_bundled',
'secret', 'addon_to', 'subevent', 'answers', 'seat', 'voucher', 'valid_from', 'valid_until',
'requested_valid_from', 'use_reusable_medium', 'discount')
'requested_valid_from', 'use_reusable_medium')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -1121,10 +1049,6 @@ class OrderPositionCreateSerializer(I18nAwareModelSerializer):
{'state': ['"{}" is not a known subdivision of the country "{}".'.format(data.get('state'), cc)]}
)
if data.get('price') is None and data.get('discount'):
raise ValidationError(
{'discount': ['You can only specify a discount if you do the price computation, but price is not set.']}
)
return data
@@ -1179,13 +1103,11 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
queryset=SalesChannel.objects.none(),
required=False,
)
tax_rounding_mode = serializers.ChoiceField(choices=ROUNDING_MODES, allow_null=True, required=False,)
locale = serializers.ChoiceField(choices=[], required=False, allow_null=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['positions'].child.fields['voucher'].queryset = self.context['event'].vouchers.all()
self.fields['positions'].child.fields['discount'].queryset = self.context['event'].discounts.all()
self.fields['customer'].queryset = self.context['event'].organizer.customers.all()
self.fields['expires'].required = False
self.fields["sales_channel"].queryset = self.context["event"].organizer.sales_channels.all()
@@ -1196,7 +1118,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
fields = ('code', 'status', 'testmode', 'email', 'phone', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
'invoice_address', 'positions', 'checkin_attention', 'checkin_text', 'payment_info', 'payment_date',
'consume_carts', 'force', 'send_email', 'simulate', 'customer', 'custom_followup_at',
'require_approval', 'valid_if_pending', 'expires', 'api_meta', 'tax_rounding_mode')
'require_approval', 'valid_if_pending', 'expires', 'api_meta')
def validate_payment_provider(self, pp):
if pp is None:
@@ -1593,22 +1515,19 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
pos.voucher_budget_use = max(listed_price - price_after_voucher, Decimal('0.00'))
order_positions = [pos_data['__instance'] for pos_data in positions_data]
if not any([p.get("discount") for p in positions_data]):
# If any discount is set by the client (i.e. pretixPOS), we do not recalculate but believe the client
# to avoid differences in end results.
discount_results = apply_discounts(
self.context['event'],
order.sales_channel,
[
(cp.item_id, cp.subevent_id, cp.subevent.date_from if cp.subevent_id else None, cp.price,
bool(cp.addon_to), cp.is_bundled, pos._voucher_discount)
for cp in order_positions
]
)
for cp, (new_price, discount) in zip(order_positions, discount_results):
if new_price != pos.price and pos._auto_generated_price:
pos.price = new_price
pos.discount = discount
discount_results = apply_discounts(
self.context['event'],
order.sales_channel,
[
(cp.item_id, cp.subevent_id, cp.subevent.date_from if cp.subevent_id else None, cp.price,
bool(cp.addon_to), cp.is_bundled, pos._voucher_discount)
for cp in order_positions
]
)
for cp, (new_price, discount) in zip(order_positions, discount_results):
if new_price != pos.price and pos._auto_generated_price:
pos.price = new_price
pos.discount = discount
# Save instances
for pos_data in positions_data:
@@ -1722,31 +1641,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
else:
f.save()
rounding_mode = validated_data.get("tax_rounding_mode")
if not rounding_mode:
if isinstance(self.context.get("auth"), Device):
# Safety fallback to avoid differences in tax reporting
brand = self.context.get("auth").software_brand or ""
if "pretixPOS" in brand or "pretixKIOSK" in brand:
rounding_mode = "line"
if not rounding_mode:
rounding_mode = self.context["event"].settings.tax_rounding
changed = apply_rounding(
rounding_mode,
self.context["event"].currency,
[*pos_map.values(), *fees]
)
for line in changed:
if isinstance(line, OrderPosition):
line.save(update_fields=[
"price", "price_includes_rounding_correction", "tax_value", "tax_value_includes_rounding_correction"
])
elif isinstance(line, OrderFee):
line.save(update_fields=[
"value", "value_includes_rounding_correction", "tax_value", "tax_value_includes_rounding_correction"
])
order.total = sum([c.price for c in pos_map.values()]) + sum([f.value for f in fees])
order.total += sum([f.value for f in fees])
if simulate:
order.fees = fees
order.positions = pos_map.values()
@@ -1810,14 +1705,12 @@ class LinePositionField(serializers.IntegerField):
class InlineInvoiceLineSerializer(I18nAwareModelSerializer):
position = LinePositionField(read_only=True)
event_date_from = serializers.DateTimeField(read_only=True, source="period_start")
event_date_to = serializers.DateTimeField(read_only=True, source="period_end")
class Meta:
model = InvoiceLine
fields = ('position', 'description', 'item', 'variation', 'subevent', 'attendee_name', 'event_date_from',
'event_date_to', 'period_start', 'period_end', 'gross_value', 'tax_value', 'tax_rate', 'tax_code',
'tax_name', 'fee_type', 'fee_internal_type', 'event_location')
'event_date_to', 'gross_value', 'tax_value', 'tax_rate', 'tax_code', 'tax_name', 'fee_type',
'fee_internal_type', 'event_location')
class InvoiceSerializer(I18nAwareModelSerializer):
@@ -1831,14 +1724,13 @@ class InvoiceSerializer(I18nAwareModelSerializer):
class Meta:
model = Invoice
fields = ('event', 'order', 'number', 'is_cancellation', 'invoice_from', 'invoice_from_name', 'invoice_from_zipcode',
'invoice_from_city', 'invoice_from_state', 'invoice_from_country', 'invoice_from_tax_id', 'invoice_from_vat_id',
'invoice_to', 'invoice_to_is_business', 'invoice_to_company', 'invoice_to_name', 'invoice_to_street',
'invoice_to_zipcode', 'invoice_to_city', 'invoice_to_state', 'invoice_to_country', 'invoice_to_vat_id',
'invoice_to_beneficiary', 'invoice_to_transmission_info', 'custom_field', 'date', 'refers', 'locale',
'invoice_from_city', 'invoice_from_country', 'invoice_from_tax_id', 'invoice_from_vat_id',
'invoice_to', 'invoice_to_company', 'invoice_to_name', 'invoice_to_street', 'invoice_to_zipcode',
'invoice_to_city', 'invoice_to_state', 'invoice_to_country', 'invoice_to_vat_id', 'invoice_to_beneficiary',
'custom_field', 'date', 'refers', 'locale',
'introductory_text', 'additional_text', 'payment_provider_text', 'payment_provider_stamp',
'footer_text', 'lines', 'foreign_currency_display', 'foreign_currency_rate',
'foreign_currency_rate_date', 'internal_reference', 'transmission_type', 'transmission_provider',
'transmission_status', 'transmission_date')
'foreign_currency_rate_date', 'internal_reference')
class OrderPaymentCreateSerializer(I18nAwareModelSerializer):

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -484,7 +484,6 @@ class OrganizerSettingsSerializer(SettingsSerializer):
'reusable_media_type_nfc_mf0aes',
'reusable_media_type_nfc_mf0aes_autocreate_giftcard',
'reusable_media_type_nfc_mf0aes_autocreate_giftcard_currency',
'reusable_media_type_nfc_mf0aes_random_uid',
]
def __init__(self, *args, **kwargs):

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -92,7 +92,6 @@ event_router.register(r'taxrules', event.TaxRuleViewSet)
event_router.register(r'seats', event.SeatViewSet)
event_router.register(r'waitinglistentries', waitinglist.WaitingListViewSet)
event_router.register(r'checkinlists', checkin.CheckinListViewSet)
event_router.register(r'checkins', checkin.CheckinViewSet)
event_router.register(r'cartpositions', cart.CartPositionViewSet)
event_router.register(r'scheduled_exports', exporters.ScheduledEventExportViewSet)
event_router.register(r'exporters', exporters.EventExportersViewSet, basename='exporters')
@@ -112,7 +111,6 @@ item_router = routers.DefaultRouter()
item_router.register(r'variations', item.ItemVariationViewSet)
item_router.register(r'addons', item.ItemAddOnViewSet)
item_router.register(r'bundles', item.ItemBundleViewSet)
item_router.register(r'program_times', item.ItemProgramTimeViewSet)
order_router = routers.DefaultRouter()
order_router.register(r'payments', order.PaymentViewSet)

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -56,8 +56,7 @@ from pretix.api.serializers.checkin import (
)
from pretix.api.serializers.item import QuestionSerializer
from pretix.api.serializers.order import (
CheckinListOrderPositionSerializer, CheckinSerializer,
FailedCheckinSerializer,
CheckinListOrderPositionSerializer, FailedCheckinSerializer,
)
from pretix.api.views import RichOrderingFilter
from pretix.api.views.order import OrderPositionFilter
@@ -97,16 +96,6 @@ with scopes_disabled():
)
return queryset.filter(expr)
class CheckinFilter(FilterSet):
created_since = django_filters.IsoDateTimeFilter(field_name='created', lookup_expr='gte')
created_before = django_filters.IsoDateTimeFilter(field_name='created', lookup_expr='lt')
datetime_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
datetime_before = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='lt')
class Meta:
model = Checkin
fields = ['successful', 'error_reason', 'list', 'type', 'gate', 'device', 'auto_checked_in']
class CheckinListViewSet(viewsets.ModelViewSet):
serializer_class = CheckinListSerializer
@@ -1091,25 +1080,3 @@ class CheckinRPCAnnulView(views.APIView):
checkin_annulled.send(ci.position.order.event, checkin=ci)
return Response({"status": "ok"}, status=status.HTTP_200_OK)
class CheckinViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CheckinSerializer
queryset = Checkin.all.none()
filter_backends = (DjangoFilterBackend, RichOrderingFilter)
filterset_class = CheckinFilter
ordering = ('created', 'id')
ordering_fields = ('created', 'datetime', 'id',)
permission = 'can_view_orders'
def get_queryset(self):
qs = Checkin.all.filter().select_related(
"position",
"device",
)
return qs
def get_serializer_context(self):
ctx = super().get_serializer_context()
ctx['event'] = self.request.event
return ctx

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -40,19 +40,19 @@ from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
from pretix.api.pagination import TotalOrderingFilter
from pretix.api.serializers.item import (
ItemAddOnSerializer, ItemBundleSerializer, ItemCategorySerializer,
ItemProgramTimeSerializer, ItemSerializer, ItemVariationSerializer,
QuestionOptionSerializer, QuestionSerializer, QuotaSerializer,
ItemSerializer, ItemVariationSerializer, QuestionOptionSerializer,
QuestionSerializer, QuotaSerializer,
)
from pretix.api.views import ConditionalListView
from pretix.base.models import (
CartPosition, Item, ItemAddOn, ItemBundle, ItemCategory, ItemProgramTime,
ItemVariation, Question, QuestionOption, Quota,
CartPosition, Item, ItemAddOn, ItemBundle, ItemCategory, ItemVariation,
Question, QuestionOption, Quota,
)
from pretix.base.services.quotas import QuotaAvailability
from pretix.helpers.dicts import merge_dicts
@@ -279,59 +279,6 @@ class ItemBundleViewSet(viewsets.ModelViewSet):
)
class ItemProgramTimeViewSet(viewsets.ModelViewSet):
serializer_class = ItemProgramTimeSerializer
queryset = ItemProgramTime.objects.none()
filter_backends = (DjangoFilterBackend, TotalOrderingFilter,)
ordering_fields = ('id',)
ordering = ('id',)
permission = None
write_permission = 'can_change_items'
@cached_property
def item(self):
return get_object_or_404(Item, pk=self.kwargs['item'], event=self.request.event)
def get_queryset(self):
if self.request.event.has_subevents:
raise ValidationError('You cannot use program times on an event series.')
return self.item.program_times.all()
def get_serializer_context(self):
ctx = super().get_serializer_context()
ctx['event'] = self.request.event
ctx['item'] = self.item
return ctx
def perform_create(self, serializer):
item = get_object_or_404(Item, pk=self.kwargs['item'], event=self.request.event)
serializer.save(item=item)
item.log_action(
'pretix.event.item.program_times.added',
user=self.request.user,
auth=self.request.auth,
data=merge_dicts(self.request.data, {'id': serializer.instance.pk})
)
def perform_update(self, serializer):
serializer.save(event=self.request.event)
serializer.instance.item.log_action(
'pretix.event.item.program_times.changed',
user=self.request.user,
auth=self.request.auth,
data=merge_dicts(self.request.data, {'id': serializer.instance.pk})
)
def perform_destroy(self, instance):
super().perform_destroy(instance)
instance.item.log_action(
'pretix.event.item.program_times.removed',
user=self.request.user,
auth=self.request.auth,
data={'start': instance.start, 'end': instance.end}
)
class ItemAddOnViewSet(viewsets.ModelViewSet):
serializer_class = ItemAddOnSerializer
queryset = ItemAddOn.objects.none()

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -88,7 +88,7 @@ from pretix.base.secrets import assign_ticket_secret
from pretix.base.services import tickets
from pretix.base.services.invoices import (
generate_cancellation, generate_invoice, invoice_pdf, invoice_qualified,
regenerate_invoice, transmit_invoice,
regenerate_invoice,
)
from pretix.base.services.mail import SendMailException
from pretix.base.services.orders import (
@@ -344,7 +344,6 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
def get_serializer_context(self):
ctx = super().get_serializer_context()
ctx['event'] = self.request.event
ctx['auth'] = self.request.auth
ctx['pdf_data'] = self.request.query_params.get('pdf_data', 'false').lower() == 'true'
return ctx
@@ -744,7 +743,7 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
user=request.user if request.user.is_authenticated else None,
auth=request.auth,
)
order_placed.send(self.request.event, order=order, bulk=False)
order_placed.send(self.request.event, order=order)
if order.status == Order.STATUS_PAID:
order_paid.send(self.request.event, order=order)
order.log_action(
@@ -765,13 +764,7 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
) and not order.invoices.last()
invoice = None
if gen_invoice:
try:
invoice = generate_invoice(order, trigger_pdf=True)
except Exception as e:
logger.exception("Could not generate invoice.")
order.log_action("pretix.event.order.invoice.failed", data={
"exception": str(e)
})
invoice = generate_invoice(order, trigger_pdf=True)
# Refresh serializer only after running signals
prefetch_related_objects([order], self._positions_prefetch(request))
@@ -1670,9 +1663,6 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
else:
mark_refunded = request.data.get('mark_canceled', False)
if not isinstance(request.data.get("comment", ""), str):
return Response({'comment': 'Invalid type.'}, status=status.HTTP_400_BAD_REQUEST)
if payment.state != OrderPayment.PAYMENT_STATE_CONFIRMED:
return Response({'detail': 'Invalid state of payment.'}, status=status.HTTP_400_BAD_REQUEST)
@@ -1699,7 +1689,6 @@ class PaymentViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
amount=amount,
provider=payment.provider,
info='{}',
comment=request.data.get("comment"),
)
payment.order.log_action('pretix.event.order.refund.created', {
'local_id': r.local_id,
@@ -1902,12 +1891,6 @@ class RetryException(APIException):
default_code = 'retry_later'
class CurrentlyInflightException(APIException):
status_code = 409
default_detail = 'The requested action is already in progress.'
default_code = 'currently_inflight'
class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = InvoiceSerializer
queryset = Invoice.objects.none()
@@ -1956,52 +1939,13 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(invoice.number)
return resp
@action(detail=True, methods=['POST'])
def transmit(self, request, **kwargs):
invoice = self.get_object()
if invoice.shredded:
raise PermissionDenied('The invoice file is no longer stored on the server.')
if invoice.transmission_status != Invoice.TRANSMISSION_STATUS_PENDING:
raise PermissionDenied('The invoice is not in pending state.')
transmit_invoice.apply_async(args=(self.request.event.pk, invoice.pk, False))
return Response(status=204)
@action(detail=True, methods=['POST'])
def retransmit(self, request, **kwargs):
invoice = self.get_object()
if invoice.shredded:
raise PermissionDenied('The invoice file is no longer stored on the server.')
with transaction.atomic(durable=True):
invoice = Invoice.objects.select_for_update(of=OF_SELF).get(pk=invoice.pk)
if invoice.transmission_status == Invoice.TRANSMISSION_STATUS_INFLIGHT:
raise CurrentlyInflightException()
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_PENDING
invoice.transmission_date = now()
invoice.save(update_fields=["transmission_status", "transmission_date"])
invoice.order.log_action(
'pretix.event.order.invoice.retransmitted',
user=self.request.user,
auth=self.request.auth,
data={
'invoice': invoice.pk,
'full_invoice_no': invoice.full_invoice_no,
}
)
transmit_invoice.apply_async(args=(self.request.event.pk, invoice.pk, True))
return Response(status=204)
@action(detail=True, methods=['POST'])
def regenerate(self, request, **kwargs):
inv = self.get_object()
if inv.canceled:
raise ValidationError('The invoice has already been canceled.')
if not inv.regenerate_allowed:
raise PermissionDenied('Invoice may not be regenerated.')
if not inv.event.settings.invoice_regenerate_allowed:
raise PermissionDenied('Invoices may not be changed after they are created.')
elif inv.shredded:
raise PermissionDenied('The invoice file is no longer stored on the server.')
elif inv.sent_to_organizer:

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -546,8 +546,7 @@ class DeviceViewSet(mixins.CreateModelMixin,
class OrganizerSettingsView(views.APIView):
permission = None
write_permission = 'can_change_organizer_settings'
permission = 'can_change_organizer_settings'
def get(self, request, *args, **kwargs):
s = OrganizerSettingsSerializer(instance=request.organizer.settings, organizer=request.organizer, context={

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -43,7 +43,6 @@ from pretix.base.services.tasks import ProfiledTask, TransactionAwareTask
from pretix.base.signals import periodic_task
from pretix.celery_app import app
from pretix.helpers import OF_SELF
from pretix.helpers.celery import get_task_priority
logger = logging.getLogger(__name__)
_ALL_EVENTS = None
@@ -79,13 +78,6 @@ class WebhookEvent:
"""
raise NotImplementedError() # NOQA
@property
def help_text(self) -> str:
"""
A human-readable description
"""
return ""
def get_all_webhook_events():
global _ALL_EVENTS
@@ -105,10 +97,9 @@ def get_all_webhook_events():
class ParametrizedWebhookEvent(WebhookEvent):
def __init__(self, action_type, verbose_name, help_text=""):
def __init__(self, action_type, verbose_name):
self._action_type = action_type
self._verbose_name = verbose_name
self._help_text = help_text
super().__init__()
@property
@@ -119,10 +110,6 @@ class ParametrizedWebhookEvent(WebhookEvent):
def verbose_name(self):
return self._verbose_name
@property
def help_text(self):
return self._help_text
class ParametrizedOrderWebhookEvent(ParametrizedWebhookEvent):
def build_payload(self, logentry: LogEntry):
@@ -174,19 +161,6 @@ class ParametrizedEventWebhookEvent(ParametrizedWebhookEvent):
}
class ParametrizedVoucherWebhookEvent(ParametrizedWebhookEvent):
def build_payload(self, logentry: LogEntry):
# do not use content_object, this is also called in deletion
return {
'notification_id': logentry.pk,
'organizer': logentry.event.organizer.slug,
'event': logentry.event.slug,
'voucher': logentry.object_id,
'action': logentry.action_type,
}
class ParametrizedSubEventWebhookEvent(ParametrizedWebhookEvent):
def build_payload(self, logentry: LogEntry):
@@ -372,9 +346,8 @@ def register_default_webhook_events(sender, **kwargs):
),
ParametrizedItemWebhookEvent(
'pretix.event.item.*',
_('Product changed'),
_('This includes product added or deleted and changes to nested objects like '
'variations or bundles.'),
_('Product changed (including product added or deleted and including changes to nested objects like '
'variations or bundles)'),
),
ParametrizedEventWebhookEvent(
'pretix.event.live.activated',
@@ -408,19 +381,6 @@ def register_default_webhook_events(sender, **kwargs):
'pretix.event.orders.waitinglist.voucher_assigned',
_('Waiting list entry received voucher'),
),
ParametrizedVoucherWebhookEvent(
'pretix.voucher.added',
_('Voucher added'),
),
ParametrizedVoucherWebhookEvent(
'pretix.voucher.changed',
_('Voucher changed'),
_('Only includes explicit changes to the voucher, not e.g. an increase of the number of redemptions.')
),
ParametrizedVoucherWebhookEvent(
'pretix.voucher.deleted',
_('Voucher deleted'),
),
ParametrizedCustomerWebhookEvent(
'pretix.customer.created',
_('Customer account created'),
@@ -440,12 +400,8 @@ def register_default_webhook_events(sender, **kwargs):
def notify_webhooks(logentry_ids: list):
if not isinstance(logentry_ids, list):
logentry_ids = [logentry_ids]
qs = LogEntry.all.select_related(
'event', 'event__organizer', 'organizer'
).order_by(
'action_type', 'organizer_id', 'event_id',
).filter(id__in=logentry_ids)
_org, _at, _ev, webhooks = None, None, None, None
qs = LogEntry.all.select_related('event', 'event__organizer', 'organizer').filter(id__in=logentry_ids)
_org, _at, webhooks = None, None, None
for logentry in qs:
if not logentry.organizer:
break # We need to know the organizer
@@ -455,7 +411,7 @@ def notify_webhooks(logentry_ids: list):
if not notification_type:
break # Ignore, no webhooks for this event type
if _org != logentry.organizer or _at != logentry.action_type or _ev != logentry.event_id or webhooks is None:
if _org != logentry.organizer or _at != logentry.action_type or webhooks is None:
_org = logentry.organizer
_at = logentry.action_type
@@ -475,10 +431,7 @@ def notify_webhooks(logentry_ids: list):
)
for wh in webhooks:
send_webhook.apply_async(
args=(logentry.id, notification_type.action_type, wh.pk),
priority=get_task_priority("notifications", logentry.organizer_id),
)
send_webhook.apply_async(args=(logentry.id, notification_type.action_type, wh.pk))
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=60, acks_late=True, autoretry_for=(DatabaseError,),)

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -43,7 +43,7 @@ class PretixBaseConfig(AppConfig):
from . import exporter # NOQA
from . import payment # NOQA
from . import exporters # NOQA
from .invoicing import pdf, transmission, email, peppol, national # NOQA
from . import invoice # NOQA
from . import notifications # NOQA
from . import email # NOQA
from .services import auth, checkin, currencies, datasync, export, mail, tickets, cart, modelimport, orders, invoices, cleanup, update_check, quotas, notifications, vouchers # NOQA

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -112,6 +112,23 @@ def oidc_validate_and_complete_config(config):
scope="openid",
))
for scope in config["scope"].split(" "):
if scope not in provider_config.get("scopes_supported", []):
raise ValidationError(_('You are requesting scope "{scope}" but provider only supports these: {scopes}.').format(
scope=scope,
scopes=", ".join(provider_config.get("scopes_supported", []))
))
if "claims_supported" in provider_config:
claims_supported = provider_config.get("claims_supported", [])
for k, v in config.items():
if k.endswith('_field') and v:
if v not in claims_supported: # https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
raise ValidationError(_('You are requesting field "{field}" but provider only supports these: {fields}.').format(
field=v,
fields=", ".join(provider_config.get("claims_supported", []))
))
if "token_endpoint_auth_methods_supported" in provider_config:
token_endpoint_auth_methods_supported = provider_config.get("token_endpoint_auth_methods_supported",
["client_secret_basic"])

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -106,7 +106,7 @@ class OutboundSyncProvider:
return str(cls.identifier)
@classmethod
def enqueue_order(cls, order, triggered_by, not_before=None, immediate=False):
def enqueue_order(cls, order, triggered_by, not_before=None):
"""
Adds an order to the sync queue. May only be called on derived classes which define an ``identifier`` attribute.
@@ -119,14 +119,10 @@ class OutboundSyncProvider:
:param order: the Order that should be synced
:param triggered_by: the reason why the order should be synced, e.g. name of the signal
(currently only used internally for logging)
:param immediate: whether a new sync task should run immediately for this order, instead
of waiting for the next periodic_task interval
:return: Return a tuple (queue_item, created), where created is a boolean
specifying whether a new queue item was created.
"""
if not hasattr(cls, 'identifier'):
raise TypeError('Call this method on a derived class that defines an "identifier" attribute.')
queue_item, created = OrderSyncQueue.objects.update_or_create(
OrderSyncQueue.objects.update_or_create(
order=order,
sync_provider=cls.identifier,
in_flight=False,
@@ -137,10 +133,6 @@ class OutboundSyncProvider:
"need_manual_retry": None,
},
)
if immediate:
from pretix.base.services.datasync import sync_single
sync_single.apply_async(args=(queue_item.pk,))
return queue_item, created
@classmethod
def get_external_link_info(cls, event, external_link_href, external_link_display_name):
@@ -260,15 +252,9 @@ class OutboundSyncProvider:
except KeyError:
with language(self.event.settings.locale):
raise SyncConfigError([_(
'Field "{field_name}" does not exist. Please check your {provider_name} settings.'
).format(field_name=key, provider_name=self.display_name)])
try:
input = inputs[field.required_input]
except KeyError:
with language(self.event.settings.locale):
raise SyncConfigError([_(
'Field "{field_name}" requires {required_input}, but only got {available_inputs}. Please check your {provider_name} settings.'
).format(field_name=key, required_input=field.required_input, available_inputs=", ".join(inputs.keys()), provider_name=self.display_name)])
'Field "{field_name}" is not valid for {available_inputs}. Please check your {provider_name} settings.'
).format(key=key, available_inputs="/".join(inputs.keys()), provider_name=self.display_name)])
input = inputs[field.required_input]
val = field.getter(input)
if isinstance(val, list):
if field.enum_opts and mapping_entry.get("value_map"):
@@ -391,7 +377,7 @@ class OutboundSyncProvider:
def sync_order(self, order):
if not self.should_sync_order(order):
logger.debug("Skipping order %r", order)
return {}
return
logger.debug("Syncing order %r", order)
positions = list(

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -24,7 +24,7 @@ from collections import namedtuple
from functools import partial
from django.db.models import Max, Q
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django.utils.translation import gettext_lazy as _
from pretix.base.models import Checkin, InvoiceAddress, Order, Question
from pretix.base.settings import PERSON_NAME_SCHEMES
@@ -132,7 +132,7 @@ CAT_PRODUCT = DataFieldCategory(20, _('Product details'))
CAT_ORDER = DataFieldCategory(21, _('Order details'))
CAT_INVOICE_ADDRESS = DataFieldCategory(22, _('Invoice address'))
CAT_EVENT = DataFieldCategory(30, _('Event information'))
CAT_EVENT_OR_SUBEVENT = DataFieldCategory(31, pgettext_lazy('subevent', 'Event or date information'))
CAT_EVENT_OR_SUBEVENT = DataFieldCategory(31, _('Event or subevent information'))
DataFieldInfo = namedtuple(
'DataFieldInfo',
@@ -524,7 +524,7 @@ def get_data_fields(event, for_model=None):
ORDER,
CAT_ORDER,
"order_locale",
_("Order locale"),
_("Order language code"),
Question.TYPE_CHOICE,
[(lc, lc) for lc in event.settings.locales],
lambda order: [order.locale],
@@ -542,7 +542,7 @@ def get_data_fields(event, for_model=None):
ORDER,
CAT_ORDER,
"presale_order_url",
_("Order link"),
_("Order URL"),
Question.TYPE_STRING,
None,
lambda order: build_absolute_uri(
@@ -557,7 +557,7 @@ def get_data_fields(event, for_model=None):
ORDER_POSITION,
CAT_ORDER_POSITION,
"presale_ticket_url",
_("Ticket link"),
_("Ticket URL"),
Question.TYPE_STRING,
None,
lambda op: build_absolute_uri(

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -24,7 +24,6 @@ from itertools import groupby
from smtplib import SMTPResponseException
from typing import TypeVar
import bleach
import css_inline
from django.conf import settings
from django.core.mail.backends.smtp import EmailBackend
@@ -35,10 +34,7 @@ from django.utils.translation import get_language, gettext_lazy as _
from pretix.base.models import Event
from pretix.base.signals import register_html_mail_renderers
from pretix.base.templatetags.rich_text import (
DEFAULT_CALLBACKS, EMAIL_RE, URL_RE, abslink_callback,
markdown_compile_email, truelink_callback,
)
from pretix.base.templatetags.rich_text import markdown_compile_email
from pretix.helpers.format import SafeFormatter, format_map
from pretix.base.services.placeholders import ( # noqa
@@ -137,24 +133,13 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
def template_name(self):
raise NotImplementedError()
def compile_markdown(self, plaintext, context=None):
return markdown_compile_email(plaintext, context=context)
def compile_markdown(self, plaintext):
return markdown_compile_email(plaintext)
def render(self, plain_body: str, plain_signature: str, subject: str, order, position, context) -> str:
body_md = self.compile_markdown(plain_body, context)
body_md = self.compile_markdown(plain_body)
if context:
linker = bleach.Linker(
url_re=URL_RE,
email_re=EMAIL_RE,
callbacks=DEFAULT_CALLBACKS + [truelink_callback, abslink_callback],
parse_email=True
)
body_md = format_map(
body_md,
context=context,
mode=SafeFormatter.MODE_RICH_TO_HTML,
linkifier=linker
)
body_md = format_map(body_md, context=context, mode=SafeFormatter.MODE_RICH_TO_HTML)
htmlctx = {
'site': settings.PRETIX_INSTANCE_NAME,
'site_url': settings.SITE_URL,

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
@@ -105,18 +105,6 @@ class BaseExporter:
"""
return False
@property
def repeatable_read(self) -> bool:
"""
If ``True``, this exporter will be run in a REPEATABLE READ transaction. This ensures consistent results for
all queries performed by the exporter, but creates a performance burden on the database server. We recommend to
disable this for exporters that take very long to run and do not rely on this behavior, such as export of lists
to CSV files.
Defaults to ``True`` for now, but default may change in future versions.
"""
return True
@property
def identifier(self) -> str:
"""

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

View File

@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.

Some files were not shown because too many files have changed in this diff Show More