diff --git a/doc/api/guides/index.rst b/doc/api/guides/index.rst
index ee2859070..b148c4df6 100644
--- a/doc/api/guides/index.rst
+++ b/doc/api/guides/index.rst
@@ -8,4 +8,5 @@ This part of the documentation contains how-to guides on some special use cases
.. toctree::
:maxdepth: 2
+ order_lifecycle
custom_checkout
diff --git a/doc/api/guides/order_lifecycle.rst b/doc/api/guides/order_lifecycle.rst
new file mode 100644
index 000000000..6e48582d6
--- /dev/null
+++ b/doc/api/guides/order_lifecycle.rst
@@ -0,0 +1,56 @@
+Understanding the life cycle of orders
+======================================
+
+When integrating pretix with other systems, it is important that you understand how orders and related objects
+such as order positions, fees, payments, refunds, and invoices work together, in order to react to their changes
+properly and map them to processes in your system.
+
+Order states
+------------
+
+Generally, an order can be in six states. For compatibility reasons, the ``status`` field only allows four values
+and the two remaining states are modeled through the ``require_approval`` field and the number of positions within
+an order. The states and their allowed changes are shown in the following graph:
+
+.. image:: /images/order_states.png
+
+
+Object types
+------------
+
+Order
+ One order represents one purchase. It's the main object you interact with and bundles all the other objects
+ together. Orders can change in many ways during their lifetime, but will never be deleted (unless ``testmode``
+ is set to ``true``).
+
+Order position
+ An order position represents one product contained in the order. Orders can usually have multiple positions.
+ There might be a parent-child relation between order positions if one position is an add-on to another position.
+ Order positions can change in many ways during their lifetime, and can also be removed or added to an order.
+
+Order fees
+ A fee represents a charge that is not related to a product. Examples include shipping fees, service fees, and
+ cancellation fees.
+ Order fees can change in many ways during their lifetime, and can also be removed or added to an order.
+
+Order payment
+ An order payment represents one payment attempt with a specific payment method and amount. An order can have
+ multiple payments attached.
+ Order payments have their own state diagram. Apart from their state and their meta information (e.g. used
+ credit card, …) they usually don't change. They may be added at any time, but will never be deleted.
+
+Order refund
+ An order payment represents one refund attempt with a specific payment method and amount. An order can have
+ multiple refunds attached.
+ Order refunds have their own state diagram. Apart from their state and their meta information (e.g. used
+ credit card, …) they usually don't change. They may be added at any time, but will never be deleted.
+
+Invoice
+ An invoice represents a legal document stating the contents of an order. While the backend technically allows
+ to update an invoice in some situations, invoices are generally considered immutable. Once they are issued,
+ they no longer change. If the order changes substantially (e.g. prices change), an invoice is canceled through
+ creation of a new invoice with the opposite amount, plus the issuance of a new invoice.
+
+Here's an example of how they all play together:
+
+.. image:: /images/order_objects.png
diff --git a/doc/api/resources/carts.rst b/doc/api/resources/carts.rst
index 3076257a6..a717880dd 100644
--- a/doc/api/resources/carts.rst
+++ b/doc/api/resources/carts.rst
@@ -42,10 +42,6 @@ seat objects The assigned se
└ seat_guid string Identifier of the seat within the seating plan
===================================== ========================== =======================================================
-.. versionchanged:: 1.17
-
- This resource has been added.
-
.. versionchanged:: 3.0
This ``seat`` attribute has been added.
diff --git a/doc/api/resources/categories.rst b/doc/api/resources/categories.rst
index 1fad90fbb..ec8613d87 100644
--- a/doc/api/resources/categories.rst
+++ b/doc/api/resources/categories.rst
@@ -25,14 +25,6 @@ is_addon boolean If ``true``, it
defining add-ons for other products.
===================================== ========================== =======================================================
-.. versionchanged:: 1.14
-
- The operations POST, PATCH, PUT and DELETE have been added.
-
-.. versionchanged:: 1.16
-
- The field ``internal_name`` has been added.
-
Endpoints
---------
diff --git a/doc/api/resources/checkinlists.rst b/doc/api/resources/checkinlists.rst
index d1a2edad5..edb564d98 100644
--- a/doc/api/resources/checkinlists.rst
+++ b/doc/api/resources/checkinlists.rst
@@ -36,22 +36,6 @@ rules object Custom check-in
exit_all_at datetime Automatically check out (i.e. perform an exit scan) at this point in time. After this happened, this property will automatically be set exactly one day into the future. Note that this field is considered "internal configuration" and if you pull the list with ``If-Modified-Since``, the daily change in this field will not trigger a response.
===================================== ========================== =======================================================
-.. versionchanged:: 1.10
-
- This resource has been added.
-
-.. versionchanged:: 1.11
-
- The ``positions`` endpoints have been added.
-
-.. versionchanged:: 1.13
-
- The ``include_pending`` field has been added.
-
-.. versionchanged:: 3.2
-
- The ``auto_checkin_sales_channels`` field has been added.
-
.. versionchanged:: 3.9
The ``subevent`` attribute may now be ``null`` inside event series. The ``allow_multiple_entries``,
@@ -68,10 +52,6 @@ exit_all_at datetime Automatically c
Endpoints
---------
-.. versionchanged:: 1.15
-
- The ``../status/`` detail endpoint has been added.
-
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/
Returns a list of all check-in lists within a given event.
@@ -380,29 +360,6 @@ Endpoints
Order position endpoints
------------------------
-.. versionchanged:: 1.15
-
- The order positions endpoint has been extended by the filter queries ``item__in``, ``variation__in``,
- ``order__status__in``, ``subevent__in``, ``addon_to__in``, and ``search``. The search for attendee names and order
- codes is now case-insensitive.
-
- The ``.../redeem/`` endpoint has been added.
-
-.. versionchanged:: 2.0
-
- The order positions endpoint has been extended by the filter queries ``voucher`` and ``voucher__code``.
-
-.. versionchanged:: 2.7
-
- The resource now contains the new attributes ``require_attention`` and ``order__status`` and accepts the new
- ``ignore_status`` filter. The ``attendee_name`` field is now "smart" (see below) and the redemption endpoint
- returns ``400`` instead of ``404`` on tickets which are known but not paid.
-
-.. versionchanged:: 3.2
-
- The ``checkins`` dict now also contains a ``auto_checked_in`` value to indicate if the check-in has been performed
- automatically by the system.
-
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/checkinlists/(list)/positions/
Returns a list of all order positions within a given event. The result is the same as
diff --git a/doc/api/resources/events.rst b/doc/api/resources/events.rst
index 207cdf8f7..25b641f6b 100644
--- a/doc/api/resources/events.rst
+++ b/doc/api/resources/events.rst
@@ -52,31 +52,6 @@ sales_channels list A list of sales
===================================== ========================== =======================================================
-.. versionchanged:: 1.7
-
- The ``meta_data`` field has been added.
-
-.. versionchanged:: 1.15
-
- The ``plugins`` field has been added.
- The operations POST, PATCH, PUT and DELETE have been added.
-
-.. versionchanged:: 2.1
-
- Filters have been added to the list of events.
-
-.. versionchanged:: 2.5
-
- The ``testmode`` attribute has been added.
-
-.. versionchanged:: 2.8
-
- When cloning events, the ``testmode`` attribute will now be cloned, too.
-
-.. versionchanged:: 3.0
-
- The attributes ``seating_plan`` and ``seat_category_mapping`` have been added.
-
.. versionchanged:: 3.3
The attributes ``geo_lat`` and ``geo_lon`` have been added.
diff --git a/doc/api/resources/invoices.rst b/doc/api/resources/invoices.rst
index 086e8b206..b54c0ecf6 100644
--- a/doc/api/resources/invoices.rst
+++ b/doc/api/resources/invoices.rst
@@ -46,24 +46,6 @@ internal_reference string Customer's refe
===================================== ========================== =======================================================
-.. versionchanged:: 1.6
-
- The attribute ``invoice_no`` has been dropped in favor of ``number`` which includes the number including the prefix,
- since the prefix can now vary. Also, invoices now need to be identified by their ``number`` instead of the raw
- number.
-
-
-.. versionchanged:: 1.7
-
- The attributes ``lines.tax_name``, ``foreign_currency_display``, ``foreign_currency_rate``, and
- ``foreign_currency_rate_date`` have been added.
-
-
-.. versionchanged:: 1.9
-
- The attribute ``internal_reference`` has been added.
-
-
.. versionchanged:: 3.4
The attribute ``lines.number`` has been added.
diff --git a/doc/api/resources/item_add-ons.rst b/doc/api/resources/item_add-ons.rst
index 2e3078eb8..b68bfcf26 100644
--- a/doc/api/resources/item_add-ons.rst
+++ b/doc/api/resources/item_add-ons.rst
@@ -28,10 +28,6 @@ multi_allowed boolean Adding the same
price_included boolean Adding this add-on to the item is free
===================================== ========================== =======================================================
-.. versionchanged:: 1.12
-
- This resource has been added.
-
Endpoints
---------
diff --git a/doc/api/resources/item_bundles.rst b/doc/api/resources/item_bundles.rst
index 1babc4bed..c66a959ef 100644
--- a/doc/api/resources/item_bundles.rst
+++ b/doc/api/resources/item_bundles.rst
@@ -30,10 +30,6 @@ designated_price money (string) Designated pric
taxation. This is not added to the price.
===================================== ========================== =======================================================
-.. versionchanged:: 2.6
-
- This resource has been added.
-
Endpoints
---------
diff --git a/doc/api/resources/item_variations.rst b/doc/api/resources/item_variations.rst
index 6f0367dff..e92ad33c7 100644
--- a/doc/api/resources/item_variations.rst
+++ b/doc/api/resources/item_variations.rst
@@ -26,14 +26,6 @@ description multi-lingual string A public descri
position integer An integer, used for sorting
===================================== ========================== =======================================================
-.. versionchanged:: 2.7
-
- The attribute ``original_price`` has been added.
-
-.. versionchanged:: 1.12
-
- This resource has been added.
-
Endpoints
---------
diff --git a/doc/api/resources/items.rst b/doc/api/resources/items.rst
index d5a478250..c9d513d80 100644
--- a/doc/api/resources/items.rst
+++ b/doc/api/resources/items.rst
@@ -118,44 +118,6 @@ bundles list of objects Definition of b
meta_data object Values set for event-specific meta data parameters.
===================================== ========================== =======================================================
-.. versionchanged:: 2.7
-
- The attribute ``original_price`` has been added for ``variations``.
-
-.. versionchanged:: 1.7
-
- The attribute ``tax_rule`` has been added. ``tax_rate`` is kept for compatibility. The attribute
- ``checkin_attention`` has been added.
-
-.. versionchanged:: 1.12
-
- The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
- The attribute ``price_included`` has been added to ``addons``.
-
-.. versionchanged:: 1.16
-
- The ``internal_name`` and ``original_price`` fields have been added.
-
-.. versionchanged:: 2.0
-
- The field ``require_approval`` has been added.
-
-.. versionchanged:: 2.3
-
- The ``sales_channels`` attribute has been added.
-
-.. versionchanged:: 2.4
-
- The ``generate_tickets`` attribute has been added.
-
-.. versionchanged:: 2.6
-
- The ``bundles`` and ``require_bundling`` attributes have been added.
-
-.. versionchanged:: 3.0
-
- The ``show_quota_left``, ``allow_waitinglist``, and ``hidden_if_available`` attributes have been added.
-
.. versionchanged:: 3.7
The attribute ``meta_data`` has been added.
diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst
index 133aab76a..443df60b3 100644
--- a/doc/api/resources/orders.rst
+++ b/doc/api/resources/orders.rst
@@ -94,60 +94,6 @@ last_modified datetime Last modificati
===================================== ========================== =======================================================
-.. versionchanged:: 1.6
-
- The ``invoice_address.country`` attribute contains a two-letter country code for all new orders. For old orders,
- a custom text might still be returned.
-
-.. versionchanged:: 1.7
-
- The attributes ``invoice_address.vat_id_validated`` and ``invoice_address.is_business`` have been added.
- The attributes ``order.payment_fee``, ``order.payment_fee_tax_rate`` and ``order.payment_fee_tax_value`` have been
- deprecated in favor of the new ``fees`` attribute but will still be served and removed in 1.9.
-
-.. versionchanged:: 1.9
-
- First write operations (``…/mark_paid/``, ``…/mark_pending/``, ``…/mark_canceled/``, ``…/mark_expired/``) have been added.
- The attribute ``invoice_address.internal_reference`` has been added.
-
-.. versionchanged:: 1.13
-
- The field ``checkin_attention`` has been added.
-
-.. versionchanged:: 1.15
-
- The attributes ``order.payment_fee``, ``order.payment_fee_tax_rate``, ``order.payment_fee_tax_value`` and
- ``order.payment_fee_tax_rule`` have finally been removed.
-
-.. versionchanged:: 1.16
-
- The attributes ``order.last_modified`` as well as the corresponding filters to the resource have been added.
- An endpoint for order creation as well as ``…/mark_refunded/`` has been added.
-
-.. versionchanged:: 2.0
-
- The ``order.payment_date`` and ``order.payment_provider`` attributes have been deprecated in favor of the new
- nested ``payments`` and ``refunds`` resources, but will still be served and removed in 2.2. The ``require_approval``
- attribute has been added, as have been the ``…/approve/`` and ``…/deny/`` endpoints.
-
-.. versionchanged:: 2.3
-
- The ``sales_channel`` attribute has been added.
-
-.. versionchanged:: 2.4
-
- ``order.status`` can no longer be ``r``, ``…/mark_canceled/`` now accepts a ``cancellation_fee`` parameter and
- ``…/mark_refunded/`` has been deprecated.
-
-.. versionchanged:: 2.5
-
- The ``testmode`` attribute has been added and ``DELETE`` has been implemented for orders.
-
-.. versionchanged:: 3.1
-
- The ``invoice_address.state`` and ``url`` attributes have been added. When creating orders through the API,
- vouchers are now supported and many fields are now optional.
-
.. versionchanged:: 3.5
The ``order.fees.canceled`` attribute has been added.
@@ -233,30 +179,6 @@ pdf_data object Data object req
``pdf_data=true`` query parameter to your request.
===================================== ========================== =======================================================
-.. versionchanged:: 1.7
-
- The attribute ``tax_rule`` has been added.
-
-.. versionchanged:: 1.11
-
- The attribute ``checkins.list`` has been added.
-
-.. versionchanged:: 1.14
-
- The attributes ``answers.question_identifier`` and ``answers.option_identifiers`` have been added.
-
-.. versionchanged:: 1.16
-
- The attributes ``pseudonymization_id`` and ``pdf_data`` have been added.
-
-.. versionchanged:: 3.0
-
- The attribute ``seat`` has been added.
-
-.. versionchanged:: 3.2
-
- The value ``auto_checked_in`` has been added to the ``checkins``-attribute.
-
.. versionchanged:: 3.3
The ``url`` of a ticket ``download`` can now also return a ``text/uri-list`` instead of a file. See
@@ -306,14 +228,6 @@ details object Payment-specifi
the object is empty.
===================================== ========================== =======================================================
-.. versionchanged:: 2.0
-
- This resource has been added.
-
-.. versionchanged:: 3.1
-
- The attributes ``payment_url`` and ``details`` have been added.
-
.. _order-refund-resource:
Order refund resource
@@ -334,17 +248,9 @@ execution_date datetime Date and time o
provider string Identification string of the payment provider
===================================== ========================== =======================================================
-.. versionchanged:: 2.0
-
- This resource has been added.
-
List of all orders
------------------
-.. versionchanged:: 1.15
-
- Filtering for emails or order codes is now case-insensitive.
-
.. versionchanged:: 3.5
The ``include_canceled_positions`` and ``include_canceled_fees`` query parameters have been added.
@@ -1450,21 +1356,6 @@ Sending e-mails
List of all order positions
---------------------------
-.. versionchanged:: 1.15
-
- The order positions endpoint has been extended by the filter queries ``item__in``, ``variation__in``,
- ``order__status__in``, ``subevent__in``, ``addon_to__in`` and ``search``. The search for attendee names and order
- codes is now case-insensitive.
-
-.. versionchanged:: 2.0
-
- The order positions endpoint has been extended by the filter queries ``voucher``, ``voucher__code`` and
- ``pseudonymization_id``.
-
-.. versionchanged:: 3.2
-
- The value ``auto_checked_in`` has been added to the ``checkins``-attribute.
-
.. versionchanged:: 3.5
The ``include_canceled_positions`` and ``include_canceled_fees`` query parameters have been added.
@@ -1804,10 +1695,6 @@ Manipulating individual positions
Order payment endpoints
-----------------------
-.. versionchanged:: 2.0
-
- These endpoints have been added.
-
.. versionchanged:: 3.6
Payments can now be created through the API.
@@ -2087,10 +1974,6 @@ Order payment endpoints
Order refund endpoints
----------------------
-.. versionchanged:: 2.0
-
- These endpoints have been added.
-
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/refunds/
Returns a list of all refunds for an order.
diff --git a/doc/api/resources/question_options.rst b/doc/api/resources/question_options.rst
index 28398244a..19def62c6 100644
--- a/doc/api/resources/question_options.rst
+++ b/doc/api/resources/question_options.rst
@@ -19,10 +19,6 @@ identifier string An arbitrary st
answer multi-lingual string The displayed value of this option
===================================== ========================== =======================================================
-.. versionchanged:: 1.12
-
- This resource has been added.
-
Endpoints
---------
diff --git a/doc/api/resources/questions.rst b/doc/api/resources/questions.rst
index f790dbce4..1ba8ee9c9 100644
--- a/doc/api/resources/questions.rst
+++ b/doc/api/resources/questions.rst
@@ -75,28 +75,6 @@ dependency_value string An old version
for one value. **Deprecated.**
===================================== ========================== =======================================================
-.. versionchanged:: 1.12
-
- The values ``D``, ``H``, and ``W`` for the field ``type`` are now allowed and the ``ask_during_checkin`` field has
- been added.
-
-.. versionchanged:: 1.14
-
- Write methods have been added. The attribute ``identifier`` has been added to both the resource itself and the
- options resource. The ``position`` attribute has been added to the options resource.
-
-.. versionchanged:: 2.7
-
- The attribute ``hidden`` and the question type ``CC`` have been added.
-
-.. versionchanged:: 3.0
-
- The attribute ``dependency_values`` has been added.
-
-.. versionchanged:: 3.1
-
- The attribute ``print_on_invoice`` has been added.
-
.. versionchanged:: 3.5
The attribute ``help_text`` has been added.
diff --git a/doc/api/resources/quotas.rst b/doc/api/resources/quotas.rst
index 2d7f416fc..b7939c358 100644
--- a/doc/api/resources/quotas.rst
+++ b/doc/api/resources/quotas.rst
@@ -30,14 +30,6 @@ release_after_exit boolean Whether the quo
have been scanned at an exit.
===================================== ========================== =======================================================
-.. versionchanged:: 1.10
-
- The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
-
-.. versionchanged:: 3.0
-
- The attributes ``close_when_sold_out`` and ``closed`` have been added.
-
.. versionchanged:: 3.10
The attribute ``release_after_exit`` has been added.
diff --git a/doc/api/resources/seatingplans.rst b/doc/api/resources/seatingplans.rst
index 4086f1ce1..2a0fdd005 100644
--- a/doc/api/resources/seatingplans.rst
+++ b/doc/api/resources/seatingplans.rst
@@ -20,10 +20,6 @@ layout object JSON representa
still evolves. The version in use can be found `here`_.
===================================== ========================== =======================================================
-.. versionchanged:: 3.0
-
- This endpoint has been added.
-
Endpoints
---------
diff --git a/doc/api/resources/subevents.rst b/doc/api/resources/subevents.rst
index e308e267c..65d559e27 100644
--- a/doc/api/resources/subevents.rst
+++ b/doc/api/resources/subevents.rst
@@ -33,6 +33,7 @@ date_to datetime The sub-event's
date_admission datetime The sub-event's admission date (or ``null``)
presale_start datetime The sub-date at which the ticket shop opens (or ``null``)
presale_end datetime The sub-date at which the ticket shop closes (or ``null``)
+frontpage_text multi-lingual string The description of the event (or ``null``)
location multi-lingual string The sub-event location (or ``null``)
geo_lat float Latitude of the location (or ``null``)
geo_lon float Longitude of the location (or ``null``)
@@ -54,25 +55,6 @@ seat_category_mapping object An object mappi
last_modified datetime Last modification of this object
===================================== ========================== =======================================================
-.. versionchanged:: 1.7
-
- The ``meta_data`` field has been added.
-
-.. versionchanged:: 2.1
-
- The ``event`` field has been added, together with filters on the list of dates and an organizer-level list.
-
-.. versionchanged:: 2.6
- The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
-
-.. versionchanged:: 2.7
-
- The attribute ``is_public`` has been added.
-
-.. versionchanged:: 3.0
-
- The attributes ``seating_plan`` and ``seat_category_mapping`` have been added.
-
.. versionchanged:: 3.3
The attributes ``geo_lat`` and ``geo_lon`` have been added.
diff --git a/doc/api/resources/taxrules.rst b/doc/api/resources/taxrules.rst
index c50ddcc96..37d84942e 100644
--- a/doc/api/resources/taxrules.rst
+++ b/doc/api/resources/taxrules.rst
@@ -24,14 +24,6 @@ home_country string Merchant countr
``null`` or empty string
===================================== ========================== =======================================================
-.. versionchanged:: 1.7
-
- This resource has been added.
-
-.. versionchanged:: 1.9
-
- The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
-
Endpoints
---------
diff --git a/doc/api/resources/vouchers.rst b/doc/api/resources/vouchers.rst
index f3d6de70b..8cdc30838 100644
--- a/doc/api/resources/vouchers.rst
+++ b/doc/api/resources/vouchers.rst
@@ -46,14 +46,6 @@ show_hidden_items boolean Only if set to
===================================== ========================== =======================================================
-.. versionchanged:: 1.9
-
- The write operations ``POST``, ``PATCH``, ``PUT``, and ``DELETE`` have been added.
-
-.. versionchanged:: 3.0
-
- The attribute ``show_hidden_items`` has been added.
-
.. versionchanged:: 3.4
The attribute ``seat`` has been added.
diff --git a/doc/development/concepts.rst b/doc/development/concepts.rst
index 3018addb4..063274376 100644
--- a/doc/development/concepts.rst
+++ b/doc/development/concepts.rst
@@ -82,11 +82,15 @@ Orders
^^^^^^
If a customer completes the checkout process, an **Order** will be created containing all the entered information.
-An order can be in one of currently four states that are listed in the diagram below:
+An order can be in one of currently six states that are listed in the diagram below:
.. image:: /images/order_states.png
-There are additional "fake" states that are displayed like states but not represented as states in the system:
+The dotted lines represent status changes that usually do not happen as part of the regular process, but can be
+performed manually in the admin backend.
+
+For historical reasons, there are only four valid values of the ``status`` field, and the two additional states are
+represented differently:
* An order is considered **canceled (with paid fee)** if it is in **paid** status but does not include any non-cancelled positions.
diff --git a/doc/images/order_objects.png b/doc/images/order_objects.png
new file mode 100644
index 000000000..880d0bc77
Binary files /dev/null and b/doc/images/order_objects.png differ
diff --git a/doc/images/order_objects.puml b/doc/images/order_objects.puml
new file mode 100644
index 000000000..1e1641a51
--- /dev/null
+++ b/doc/images/order_objects.puml
@@ -0,0 +1,34 @@
+@startuml
+
+participant User
+collections "OrderPayment\nOrderRefund" as P
+collections "Order\nOrderPosition" as O
+collections "Invoice\nInvoiceLine" as I
+
+User -> O: Order placed (€100)
+rnote over O #6DD96D: Order A1B2C\nstatus = **n**\ntotal = €100
+O -> P: Payment created
+O -> I: Invoice created\n(can also happen later)
+rnote over I #6DD96D: Invoice 00001\n€100
+rnote over P #6DD96D: OrderPayment A1B2C-P-1\nstate = **created**
+P -> User: Payment details (web, email)
+User -> P: Payment performed
+rnote over P #EFF46B: OrderPayment A1B2C-P-1\nstate = **confirmed**
+P -> O: Order marked as paid
+rnote over O #EFF46B: Order A1B2C\nstatus = **p**\ntotal = €100
+User -> O: Data change (e.g. invoice address)
+O -> I: Invoice reissued
+rnote over I #6DD96D: Invoice 00002\n€-100
+rnote over I #6DD96D: Invoice 00003\n€100
+rnote over O #EFF46B: Order A1B2C\nstatus = **p**\ntotal = €100
+User -> O: Order canceled
+rnote over O #EFF46B: Order A1B2C\nstatus = **c**
+O -> I: Invoice canceled
+rnote over I #6DD96D: Invoice 00004\n€-100
+O -> P: Refund started
+rnote over P #6DD96D: OrderRefund\nA1B2C-R-1\nstate = **created**
+P -> User: Money sent
+rnote over P #EFF46B: OrderRefund\nA1B2C-R-1\nstate = **done**
+
+@enduml
+
diff --git a/doc/images/order_states.png b/doc/images/order_states.png
index 84e9b0eb1..4c5cc4a3c 100644
Binary files a/doc/images/order_states.png and b/doc/images/order_states.png differ
diff --git a/doc/images/order_states.puml b/doc/images/order_states.puml
index 5465725af..a1ef55fac 100644
--- a/doc/images/order_states.puml
+++ b/doc/images/order_states.puml
@@ -1,19 +1,39 @@
@startuml
-Pending: Order is expecting payment\nOrder reduces quotas
-Expired: Payment period is over\nOrder does not affect quotas
-Paid: Order was successful\nOrder reduces quotas
-Canceled: Order has been canceled\nOrder does not affect quotas
+state "Approval Pending" as AP
+state "Canceled (with paid fee)" as CP
+AP: status = "n"
+AP: require_approval = true
+Pending: status = "n"
+Pending: require_approval = false
+Pending: Tickets reserved: yes
+Expired: status = "e"
+Expired: Tickets reserved: no
+Paid: status = "p"
+Paid: count(positions | !canceled) > 0
+Paid: Tickets reserved: yes
+CP: status = "p"
+CP: count(positions | !canceled) = 0
+Canceled: status = "c"
+Canceled: Tickets reserved: no
-[*] --> Pending: customer\nplaces order
-Pending --> Paid: successful payment
-Pending --> Expired: automatically\nor manually\non admin action
-Expired --> Paid: if payment is received\nonly if quota left
-Expired --> Canceled
-Expired --> Pending: manually\non admin action
-Paid --> Canceled: manually on\nadmin action\nor if an external\npayment provider\nnotifies about a\npayment refund
-Pending --> Canceled: on admin or\ncustomer action
-Paid -> Pending: manually on admin action
-[*] --> Paid: customer\nplaces free order
+
+[*] -> Pending: order placed\ntotal > 0
+[*] -> Paid: order placed\ntotal = 0
+[*] -> AP: order placed\napproval required
+Pending --> Paid: order paid
+Pending --> Expired: after payment\ndeadline
+Expired --> Paid: order paid\n(only if quota left)
+Expired -[dashed]-> Canceled
+Expired -[dashed]-> Pending: order extended
+Paid --> Canceled: order canceled
+Pending --> Canceled: order canceled
+Paid -[dashed]-> Pending: refund
+AP --> Pending: order approved
+AP --> Canceled: order denied
+Paid --> CP: order canceled\n(with cancellation fee)
+Canceled -[dashed]-> Pending: order reactivated
+Canceled -[dashed]-> Paid: order reactivated
+CP -[dashed]-> Canceled: fee canceled
@enduml
diff --git a/doc/plugins/badges.rst b/doc/plugins/badges.rst
index 51be4ba3b..e46ab7e91 100644
--- a/doc/plugins/badges.rst
+++ b/doc/plugins/badges.rst
@@ -22,10 +22,6 @@ item_assignments list of objects Products this l
└ item integer Item ID
===================================== ========================== =======================================================
-.. versionchanged:: 1.16
-
- This resource has been added.
-
Endpoints
---------
diff --git a/doc/plugins/ticketoutputpdf.rst b/doc/plugins/ticketoutputpdf.rst
index ccb12327e..ab5e0cce0 100644
--- a/doc/plugins/ticketoutputpdf.rst
+++ b/doc/plugins/ticketoutputpdf.rst
@@ -24,14 +24,6 @@ item_assignments list of objects Products this l
└ item integer Item ID
===================================== ========================== =======================================================
-.. versionchanged:: 1.16
-
- This resource has been added.
-
-.. versionchanged:: 2.3
-
- The ``item_assignments.sales_channel`` field has been added.
-
Endpoints
---------
diff --git a/doc/user/events/widget.rst b/doc/user/events/widget.rst
index ad5db038e..6e5e55053 100644
--- a/doc/user/events/widget.rst
+++ b/doc/user/events/widget.rst
@@ -437,11 +437,6 @@ Hosted or pretix Enterprise are active, you can pass the following fields:
-.. versionchanged:: 2.3
-
- Data passing options have been added in pretix 2.3. If you use a self-hosted version of pretix, they only work
- fully if you configured a redis server.
-
.. versionchanged:: 3.6
Dynamically opening the widget has been added in pretix 3.6.
diff --git a/src/pretix/api/serializers/event.py b/src/pretix/api/serializers/event.py
index 036fb76dc..b3575d584 100644
--- a/src/pretix/api/serializers/event.py
+++ b/src/pretix/api/serializers/event.py
@@ -409,8 +409,8 @@ class SubEventSerializer(I18nAwareModelSerializer):
model = SubEvent
fields = ('id', 'name', 'date_from', 'date_to', 'active', 'date_admission',
'presale_start', 'presale_end', 'location', 'geo_lat', 'geo_lon', 'event', 'is_public',
- 'seating_plan', 'item_price_overrides', 'variation_price_overrides', 'meta_data',
- 'seat_category_mapping', 'last_modified')
+ 'frontpage_text', 'seating_plan', 'item_price_overrides', 'variation_price_overrides',
+ 'meta_data', 'seat_category_mapping', 'last_modified')
def validate(self, data):
data = super().validate(data)
diff --git a/src/pretix/base/email.py b/src/pretix/base/email.py
index 2fae8111a..5b252dc9d 100644
--- a/src/pretix/base/email.py
+++ b/src/pretix/base/email.py
@@ -468,7 +468,8 @@ def base_placeholders(sender, **kwargs):
'68CYU2H6ZTP3WLK5'
),
SimpleFunctionalMailTextPlaceholder(
- 'voucher_list', ['voucher_list'], lambda voucher_list: '\n'.join(voucher_list),
+ # join vouchers with two spaces at end of line so markdown-parser inserts a
+ 'voucher_list', ['voucher_list'], lambda voucher_list: ' \n'.join(voucher_list),
' 68CYU2H6ZTP3WLK5\n 7MB94KKPVEPSMVF2'
),
SimpleFunctionalMailTextPlaceholder(
diff --git a/src/pretix/base/exporter.py b/src/pretix/base/exporter.py
index 91da572d9..4338e7936 100644
--- a/src/pretix/base/exporter.py
+++ b/src/pretix/base/exporter.py
@@ -1,4 +1,5 @@
import io
+import re
import tempfile
from collections import OrderedDict, namedtuple
from decimal import Decimal
@@ -10,11 +11,21 @@ from django.db.models import QuerySet
from django.utils.formats import localize
from django.utils.translation import gettext, gettext_lazy as _
from openpyxl import Workbook
-from openpyxl.cell.cell import KNOWN_TYPES
+from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE, KNOWN_TYPES
from pretix.base.models import Event
+def excel_safe(val):
+ if not isinstance(val, KNOWN_TYPES):
+ val = str(val)
+
+ if isinstance(val, str):
+ val = re.sub(ILLEGAL_CHARACTERS_RE, '', val)
+
+ return val
+
+
class BaseExporter:
"""
This is the base class for all data exporters
@@ -181,7 +192,7 @@ class ListExporter(BaseExporter):
total = line.total
continue
ws.append([
- str(val) if not isinstance(val, KNOWN_TYPES) else val
+ excel_safe(val) if not isinstance(val, KNOWN_TYPES) else val
for val in line
])
if total:
@@ -301,7 +312,7 @@ class MultiSheetListExporter(ListExporter):
total = line.total
continue
ws.append([
- str(val) if not isinstance(val, KNOWN_TYPES) else val
+ excel_safe(val)
for val in line
])
if total:
diff --git a/src/pretix/base/models/organizer.py b/src/pretix/base/models/organizer.py
index c77988187..eb0b09d88 100644
--- a/src/pretix/base/models/organizer.py
+++ b/src/pretix/base/models/organizer.py
@@ -4,6 +4,7 @@ from datetime import date, datetime, time
from django.core.validators import MinLengthValidator, RegexValidator
from django.db import models
from django.db.models import Exists, OuterRef, Q
+from django.urls import reverse
from django.utils.crypto import get_random_string
from django.utils.functional import cached_property
from django.utils.timezone import get_current_timezone, make_aware, now
@@ -88,6 +89,15 @@ class Organizer(LoggedModel):
return ObjectRelatedCache(self)
+ @cached_property
+ def all_logentries_link(self):
+ return reverse(
+ 'control:organizer.log',
+ kwargs={
+ 'organizer': self.slug,
+ }
+ )
+
@property
def has_gift_cards(self):
return self.cache.get_or_set(
diff --git a/src/pretix/control/forms/filter.py b/src/pretix/control/forms/filter.py
index fbca154f3..19db3f309 100644
--- a/src/pretix/control/forms/filter.py
+++ b/src/pretix/control/forms/filter.py
@@ -1,4 +1,4 @@
-from datetime import datetime, time
+from datetime import datetime, time, timedelta
from decimal import Decimal
from urllib.parse import urlencode
@@ -766,10 +766,15 @@ class SubEventFilterForm(FilterForm):
),
required=False
)
- date = forms.DateField(
- label=_('Date'),
+ date_from = forms.DateField(
+ label=_('Date from'),
required=False,
- widget=DatePickerWidget
+ widget=DatePickerWidget,
+ )
+ date_until = forms.DateField(
+ label=_('Date until'),
+ required=False,
+ widget=DatePickerWidget,
)
weekday = forms.ChoiceField(
label=_('Weekday'),
@@ -796,7 +801,8 @@ class SubEventFilterForm(FilterForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['date'].widget = DatePickerWidget()
+ self.fields['date_from'].widget = DatePickerWidget()
+ self.fields['date_until'].widget = DatePickerWidget()
def filter_qs(self, qs):
fdata = self.cleaned_data
@@ -838,19 +844,21 @@ class SubEventFilterForm(FilterForm):
Q(name__icontains=i18ncomp(query)) | Q(location__icontains=query)
)
- if fdata.get('date'):
- date_start = make_aware(datetime.combine(
- fdata.get('date'),
+ if fdata.get('date_until'):
+ date_end = make_aware(datetime.combine(
+ fdata.get('date_until') + timedelta(days=1),
time(hour=0, minute=0, second=0, microsecond=0)
), get_current_timezone())
- date_end = make_aware(datetime.combine(
- fdata.get('date'),
- time(hour=23, minute=59, second=59, microsecond=999999)
- ), get_current_timezone())
qs = qs.filter(
- Q(date_to__isnull=True, date_from__gte=date_start, date_from__lte=date_end) |
- Q(date_to__isnull=False, date_from__lte=date_end, date_to__gte=date_start)
+ Q(date_to__isnull=True, date_from__lt=date_end) |
+ Q(date_to__isnull=False, date_to__lt=date_end)
)
+ if fdata.get('date_from'):
+ date_start = make_aware(datetime.combine(
+ fdata.get('date_from'),
+ time(hour=0, minute=0, second=0, microsecond=0)
+ ), get_current_timezone())
+ qs = qs.filter(date_from__gte=date_start)
if fdata.get('ordering'):
qs = qs.order_by(self.get_order_by())
diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py
index 9f6d3d968..e79931245 100644
--- a/src/pretix/control/forms/orders.py
+++ b/src/pretix/control/forms/orders.py
@@ -104,7 +104,7 @@ class ConfirmPaymentForm(forms.Form):
class CancelForm(ConfirmPaymentForm):
send_email = forms.BooleanField(
required=False,
- label=_('Notify user by e-mail'),
+ label=_('Notify customer by email'),
initial=True
)
cancellation_fee = forms.DecimalField(
@@ -139,6 +139,11 @@ class CancelForm(ConfirmPaymentForm):
class MarkPaidForm(ConfirmPaymentForm):
+ send_email = forms.BooleanField(
+ required=False,
+ label=_('Notify customer by email'),
+ initial=True
+ )
amount = forms.DecimalField(
required=True,
max_digits=10, decimal_places=2,
diff --git a/src/pretix/control/forms/renderers.py b/src/pretix/control/forms/renderers.py
index 7b7edc227..41a55bdbe 100644
--- a/src/pretix/control/forms/renderers.py
+++ b/src/pretix/control/forms/renderers.py
@@ -1,4 +1,4 @@
-from bootstrap3.renderers import FieldRenderer
+from bootstrap3.renderers import FieldRenderer, InlineFieldRenderer
from bootstrap3.text import text_value
from django.forms import CheckboxInput
from django.forms.utils import flatatt
@@ -58,3 +58,40 @@ class ControlFieldRenderer(FieldRenderer):
optional=not required and not isinstance(self.widget, CheckboxInput)
) + html
return html
+
+
+class BulkEditMixin:
+
+ def __init__(self, *args, **kwargs):
+ kwargs['layout'] = self.layout
+ super().__init__(*args, **kwargs)
+
+ def wrap_field(self, html):
+ field_class = self.get_field_class()
+ name = '{}{}'.format(self.field.form.prefix, self.field.name)
+ checked = self.field.form.data and name in self.field.form.data.getlist('_bulk')
+ html = (
+ '