diff --git a/.licenseheader b/.licenseheader
index 39009128b..5cbdfddde 100644
--- a/.licenseheader
+++ b/.licenseheader
@@ -1,7 +1,7 @@
This file is part of pretix (Community Edition).
-Copyright (C) 2014-2020 Raphael Michel and contributors
-Copyright (C) 2020-2021 rami.io GmbH and contributors
+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.
diff --git a/doc/api/resources/invoices.rst b/doc/api/resources/invoices.rst
index 9188b73c2..de9245941 100644
--- a/doc/api/resources/invoices.rst
+++ b/doc/api/resources/invoices.rst
@@ -80,17 +80,12 @@ 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).
-├ 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.
+├ 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_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
@@ -274,6 +269,8 @@ 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",
@@ -420,6 +417,8 @@ 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",
diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst
index dc9efef72..2894d16c6 100644
--- a/doc/api/resources/orders.rst
+++ b/doc/api/resources/orders.rst
@@ -1030,8 +1030,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!
+ 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`)
@@ -1058,6 +1058,7 @@ 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``
@@ -2508,6 +2509,7 @@ Order payment endpoints
{
"amount": "23.00",
+ "comment": "Overpayment",
"mark_canceled": false
}
diff --git a/doc/development/api/general.rst b/doc/development/api/general.rst
index 636de683c..ce0bcf0dc 100644
--- a/doc/development/api/general.rst
+++ b/doc/development/api/general.rst
@@ -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, 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, build_invoice_data, invoice_line_text
Check-ins
"""""""""
diff --git a/pyproject.toml b/pyproject.toml
index e6e5bf13d..c1a12ddf8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,7 +28,7 @@ classifiers = [
dependencies = [
"arabic-reshaper==3.0.0", # Support for Arabic in reportlab
"babel",
- "BeautifulSoup4==4.13.*",
+ "BeautifulSoup4==4.14.*",
"bleach==6.2.*",
"celery==5.5.*",
"chardet==5.2.*",
@@ -76,12 +76,12 @@ dependencies = [
"phonenumberslite==9.0.*",
"Pillow==11.3.*",
"pretix-plugin-build",
- "protobuf==6.32.*",
+ "protobuf==6.33.*",
"psycopg2-binary",
"pycountry",
"pycparser==2.23",
"pycryptodome==3.23.*",
- "pypdf==6.0.*",
+ "pypdf==6.1.*",
"python-bidi==0.6.*", # Support for Arabic in reportlab
"python-dateutil==2.9.*",
"pytz",
@@ -91,8 +91,8 @@ dependencies = [
"redis==6.4.*",
"reportlab==4.4.*",
"requests==2.32.*",
- "sentry-sdk==2.38.*",
- "sepaxml==2.6.*",
+ "sentry-sdk==2.42.*",
+ "sepaxml==2.7.*",
"stripe==7.9.*",
"text-unidecode==1.*",
"tlds>=2020041600",
@@ -107,13 +107,13 @@ dependencies = [
[project.optional-dependencies]
memcached = ["pylibmc"]
dev = [
- "aiohttp==3.12.*",
+ "aiohttp==3.13.*",
"coverage",
"coveralls",
- "fakeredis==2.31.*",
+ "fakeredis==2.32.*",
"flake8==7.3.*",
"freezegun",
- "isort==6.0.*",
+ "isort==6.1.*",
"pep8-naming==0.15.*",
"potypo",
"pytest-asyncio>=0.24",
diff --git a/src/manage.py b/src/manage.py
index 58e32fac2..8b393c449 100755
--- a/src/manage.py
+++ b/src/manage.py
@@ -2,8 +2,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/__init__.py b/src/pretix/__init__.py
index 1c6c57b98..ac9cd86de 100644
--- a/src/pretix/__init__.py
+++ b/src/pretix/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -19,4 +19,4 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
-__version__ = "2025.8.0"
+__version__ = "2025.9.0"
diff --git a/src/pretix/__main__.py b/src/pretix/__main__.py
index 53231751d..f064608c0 100644
--- a/src/pretix/__main__.py
+++ b/src/pretix/__main__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/_base_settings.py b/src/pretix/_base_settings.py
index 97d79b036..2931c7e41 100644
--- a/src/pretix/_base_settings.py
+++ b/src/pretix/_base_settings.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/_build.py b/src/pretix/_build.py
index 884384a37..de9e2900c 100644
--- a/src/pretix/_build.py
+++ b/src/pretix/_build.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/_build_settings.py b/src/pretix/_build_settings.py
index c03f56a1a..5c04e511d 100644
--- a/src/pretix/_build_settings.py
+++ b/src/pretix/_build_settings.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/__init__.py b/src/pretix/api/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/api/__init__.py
+++ b/src/pretix/api/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/apps.py b/src/pretix/api/apps.py
index 2af7c6175..9f06f9128 100644
--- a/src/pretix/api/apps.py
+++ b/src/pretix/api/apps.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/auth/__init__.py b/src/pretix/api/auth/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/api/auth/__init__.py
+++ b/src/pretix/api/auth/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/auth/device.py b/src/pretix/api/auth/device.py
index dd9b4c287..00fc03ba0 100644
--- a/src/pretix/api/auth/device.py
+++ b/src/pretix/api/auth/device.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/auth/devicesecurity.py b/src/pretix/api/auth/devicesecurity.py
index d6be03e72..18a99336b 100644
--- a/src/pretix/api/auth/devicesecurity.py
+++ b/src/pretix/api/auth/devicesecurity.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/auth/permission.py b/src/pretix/api/auth/permission.py
index e023a1495..802781d00 100644
--- a/src/pretix/api/auth/permission.py
+++ b/src/pretix/api/auth/permission.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/auth/session.py b/src/pretix/api/auth/session.py
index 431741963..7b2eff806 100644
--- a/src/pretix/api/auth/session.py
+++ b/src/pretix/api/auth/session.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/auth/token.py b/src/pretix/api/auth/token.py
index cb00462b5..ed0d1829e 100644
--- a/src/pretix/api/auth/token.py
+++ b/src/pretix/api/auth/token.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/exception.py b/src/pretix/api/exception.py
index ec6b317df..0358fba9a 100644
--- a/src/pretix/api/exception.py
+++ b/src/pretix/api/exception.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/filters.py b/src/pretix/api/filters.py
index e9217139f..c3dc68ea1 100644
--- a/src/pretix/api/filters.py
+++ b/src/pretix/api/filters.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/middleware.py b/src/pretix/api/middleware.py
index ff4d37c8f..53bae03b4 100644
--- a/src/pretix/api/middleware.py
+++ b/src/pretix/api/middleware.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/models.py b/src/pretix/api/models.py
index 39787fc30..a6c202e57 100644
--- a/src/pretix/api/models.py
+++ b/src/pretix/api/models.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/oauth.py b/src/pretix/api/oauth.py
index fa93e1647..f1482c4d7 100644
--- a/src/pretix/api/oauth.py
+++ b/src/pretix/api/oauth.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/pagination.py b/src/pretix/api/pagination.py
index 4f8a55579..8cc331775 100644
--- a/src/pretix/api/pagination.py
+++ b/src/pretix/api/pagination.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/__init__.py b/src/pretix/api/serializers/__init__.py
index 76933c4e6..ea435914a 100644
--- a/src/pretix/api/serializers/__init__.py
+++ b/src/pretix/api/serializers/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/cart.py b/src/pretix/api/serializers/cart.py
index 38d064684..74dc5242b 100644
--- a/src/pretix/api/serializers/cart.py
+++ b/src/pretix/api/serializers/cart.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/checkin.py b/src/pretix/api/serializers/checkin.py
index c28dfada9..63759c016 100644
--- a/src/pretix/api/serializers/checkin.py
+++ b/src/pretix/api/serializers/checkin.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/discount.py b/src/pretix/api/serializers/discount.py
index 9cf4ae748..e6f5d5f0a 100644
--- a/src/pretix/api/serializers/discount.py
+++ b/src/pretix/api/serializers/discount.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/event.py b/src/pretix/api/serializers/event.py
index e271ecc9c..680d1bd5d 100644
--- a/src/pretix/api/serializers/event.py
+++ b/src/pretix/api/serializers/event.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -805,6 +805,7 @@ class EventSettingsSerializer(SettingsSerializer):
'invoice_reissue_after_modify',
'invoice_include_free',
'invoice_generate',
+ 'invoice_period',
'invoice_numbers_consecutive',
'invoice_numbers_prefix',
'invoice_numbers_prefix_cancellations',
diff --git a/src/pretix/api/serializers/exporters.py b/src/pretix/api/serializers/exporters.py
index 785e607a0..b5f99ad46 100644
--- a/src/pretix/api/serializers/exporters.py
+++ b/src/pretix/api/serializers/exporters.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/fields.py b/src/pretix/api/serializers/fields.py
index db8858a22..d3cc5f1b8 100644
--- a/src/pretix/api/serializers/fields.py
+++ b/src/pretix/api/serializers/fields.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/forms.py b/src/pretix/api/serializers/forms.py
index a7817471c..d577851cc 100644
--- a/src/pretix/api/serializers/forms.py
+++ b/src/pretix/api/serializers/forms.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/i18n.py b/src/pretix/api/serializers/i18n.py
index 3fc91e041..56700d279 100644
--- a/src/pretix/api/serializers/i18n.py
+++ b/src/pretix/api/serializers/i18n.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/item.py b/src/pretix/api/serializers/item.py
index 1c40eb13c..3b1dd9d9b 100644
--- a/src/pretix/api/serializers/item.py
+++ b/src/pretix/api/serializers/item.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -550,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'))
+ Question.clean_items(event, full_data.get('items') or [])
return data
def validate_options(self, value):
@@ -566,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)
diff --git a/src/pretix/api/serializers/media.py b/src/pretix/api/serializers/media.py
index e4b3d09c1..8285fade4 100644
--- a/src/pretix/api/serializers/media.py
+++ b/src/pretix/api/serializers/media.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/order.py b/src/pretix/api/serializers/order.py
index 68c7f7e9f..b58754ed9 100644
--- a/src/pretix/api/serializers/order.py
+++ b/src/pretix/api/serializers/order.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -1005,7 +1005,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')
+ 'requested_valid_from', 'use_reusable_medium', 'discount')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -1101,6 +1101,10 @@ 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
@@ -1160,6 +1164,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
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()
@@ -1567,19 +1572,22 @@ 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]
- 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
+ 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
# Save instances
for pos_data in positions_data:
@@ -1757,12 +1765,14 @@ 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', 'gross_value', 'tax_value', 'tax_rate', 'tax_code', 'tax_name', 'fee_type',
- 'fee_internal_type', 'event_location')
+ 'event_date_to', 'period_start', 'period_end', 'gross_value', 'tax_value', 'tax_rate', 'tax_code',
+ 'tax_name', 'fee_type', 'fee_internal_type', 'event_location')
class InvoiceSerializer(I18nAwareModelSerializer):
diff --git a/src/pretix/api/serializers/orderchange.py b/src/pretix/api/serializers/orderchange.py
index e8fb7820d..10e84daf3 100644
--- a/src/pretix/api/serializers/orderchange.py
+++ b/src/pretix/api/serializers/orderchange.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/organizer.py b/src/pretix/api/serializers/organizer.py
index 58deb71dc..aee83af95 100644
--- a/src/pretix/api/serializers/organizer.py
+++ b/src/pretix/api/serializers/organizer.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/settings.py b/src/pretix/api/serializers/settings.py
index cb9a31080..435b964db 100644
--- a/src/pretix/api/serializers/settings.py
+++ b/src/pretix/api/serializers/settings.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/shredders.py b/src/pretix/api/serializers/shredders.py
index 6a574af15..385029e0a 100644
--- a/src/pretix/api/serializers/shredders.py
+++ b/src/pretix/api/serializers/shredders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/voucher.py b/src/pretix/api/serializers/voucher.py
index 425df1eb8..038c32e8a 100644
--- a/src/pretix/api/serializers/voucher.py
+++ b/src/pretix/api/serializers/voucher.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/waitinglist.py b/src/pretix/api/serializers/waitinglist.py
index 6dbf6891b..9cc47b012 100644
--- a/src/pretix/api/serializers/waitinglist.py
+++ b/src/pretix/api/serializers/waitinglist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/serializers/webhooks.py b/src/pretix/api/serializers/webhooks.py
index 756f15611..7849d91ae 100644
--- a/src/pretix/api/serializers/webhooks.py
+++ b/src/pretix/api/serializers/webhooks.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/signals.py b/src/pretix/api/signals.py
index 1f69fad60..763b7ffc7 100644
--- a/src/pretix/api/signals.py
+++ b/src/pretix/api/signals.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/urls.py b/src/pretix/api/urls.py
index b1cb10edd..15c654567 100644
--- a/src/pretix/api/urls.py
+++ b/src/pretix/api/urls.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/__init__.py b/src/pretix/api/views/__init__.py
index 04728f638..7bcaf8f26 100644
--- a/src/pretix/api/views/__init__.py
+++ b/src/pretix/api/views/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/cart.py b/src/pretix/api/views/cart.py
index 8339822da..9a02a86db 100644
--- a/src/pretix/api/views/cart.py
+++ b/src/pretix/api/views/cart.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/checkin.py b/src/pretix/api/views/checkin.py
index ec31e3b50..02304446d 100644
--- a/src/pretix/api/views/checkin.py
+++ b/src/pretix/api/views/checkin.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/device.py b/src/pretix/api/views/device.py
index 6db8e5a56..7482d1be7 100644
--- a/src/pretix/api/views/device.py
+++ b/src/pretix/api/views/device.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/discount.py b/src/pretix/api/views/discount.py
index d3545d4be..4504d0381 100644
--- a/src/pretix/api/views/discount.py
+++ b/src/pretix/api/views/discount.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/event.py b/src/pretix/api/views/event.py
index 19b2fb7d2..b61771bdb 100644
--- a/src/pretix/api/views/event.py
+++ b/src/pretix/api/views/event.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/exporters.py b/src/pretix/api/views/exporters.py
index af21077c2..63344b21e 100644
--- a/src/pretix/api/views/exporters.py
+++ b/src/pretix/api/views/exporters.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/idempotency.py b/src/pretix/api/views/idempotency.py
index 4cbe83dd5..54ac143a4 100644
--- a/src/pretix/api/views/idempotency.py
+++ b/src/pretix/api/views/idempotency.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/item.py b/src/pretix/api/views/item.py
index 83e0dc19b..19661c60e 100644
--- a/src/pretix/api/views/item.py
+++ b/src/pretix/api/views/item.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/media.py b/src/pretix/api/views/media.py
index 4954a9fe0..1569ee289 100644
--- a/src/pretix/api/views/media.py
+++ b/src/pretix/api/views/media.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/oauth.py b/src/pretix/api/views/oauth.py
index 88c45fb53..acd8b94c0 100644
--- a/src/pretix/api/views/oauth.py
+++ b/src/pretix/api/views/oauth.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/order.py b/src/pretix/api/views/order.py
index faded5bec..f818192ae 100644
--- a/src/pretix/api/views/order.py
+++ b/src/pretix/api/views/order.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -743,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)
+ order_placed.send(self.request.event, order=order, bulk=False)
if order.status == Order.STATUS_PAID:
order_paid.send(self.request.event, order=order)
order.log_action(
@@ -764,7 +764,13 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
) and not order.invoices.last()
invoice = None
if gen_invoice:
- invoice = generate_invoice(order, trigger_pdf=True)
+ 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)
+ })
# Refresh serializer only after running signals
prefetch_related_objects([order], self._positions_prefetch(request))
@@ -1663,6 +1669,9 @@ 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)
@@ -1689,6 +1698,7 @@ 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,
diff --git a/src/pretix/api/views/organizer.py b/src/pretix/api/views/organizer.py
index bf73d51cd..f600086e1 100644
--- a/src/pretix/api/views/organizer.py
+++ b/src/pretix/api/views/organizer.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/shredders.py b/src/pretix/api/views/shredders.py
index 353ca0cf1..acb34fa83 100644
--- a/src/pretix/api/views/shredders.py
+++ b/src/pretix/api/views/shredders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/upload.py b/src/pretix/api/views/upload.py
index bd75a7d98..e6426de64 100644
--- a/src/pretix/api/views/upload.py
+++ b/src/pretix/api/views/upload.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/user.py b/src/pretix/api/views/user.py
index 361ca46a2..142563ecd 100644
--- a/src/pretix/api/views/user.py
+++ b/src/pretix/api/views/user.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/version.py b/src/pretix/api/views/version.py
index 9aea65a98..2ac2edb02 100644
--- a/src/pretix/api/views/version.py
+++ b/src/pretix/api/views/version.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/voucher.py b/src/pretix/api/views/voucher.py
index 3fcb235e2..c0c0c1016 100644
--- a/src/pretix/api/views/voucher.py
+++ b/src/pretix/api/views/voucher.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/waitinglist.py b/src/pretix/api/views/waitinglist.py
index 2683e496a..f645a5e56 100644
--- a/src/pretix/api/views/waitinglist.py
+++ b/src/pretix/api/views/waitinglist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/views/webhooks.py b/src/pretix/api/views/webhooks.py
index b2d18971e..f0c781523 100644
--- a/src/pretix/api/views/webhooks.py
+++ b/src/pretix/api/views/webhooks.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/api/webhooks.py b/src/pretix/api/webhooks.py
index 2dcf525e9..b14bd7139 100644
--- a/src/pretix/api/webhooks.py
+++ b/src/pretix/api/webhooks.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -439,8 +439,12 @@ 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').filter(id__in=logentry_ids)
- _org, _at, webhooks = None, None, None
+ 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
for logentry in qs:
if not logentry.organizer:
break # We need to know the organizer
@@ -450,7 +454,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 webhooks is None:
+ if _org != logentry.organizer or _at != logentry.action_type or _ev != logentry.event_id or webhooks is None:
_org = logentry.organizer
_at = logentry.action_type
diff --git a/src/pretix/base/__init__.py b/src/pretix/base/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/__init__.py
+++ b/src/pretix/base/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/addressvalidation.py b/src/pretix/base/addressvalidation.py
index aa5550e19..9a2959f76 100644
--- a/src/pretix/base/addressvalidation.py
+++ b/src/pretix/base/addressvalidation.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/apps.py b/src/pretix/base/apps.py
index 66baca9ab..1852c0c35 100644
--- a/src/pretix/base/apps.py
+++ b/src/pretix/base/apps.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/auth.py b/src/pretix/base/auth.py
index 6750ea825..f504729ee 100644
--- a/src/pretix/base/auth.py
+++ b/src/pretix/base/auth.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/banlist.py b/src/pretix/base/banlist.py
index 6b26ee1ec..e22f34e21 100644
--- a/src/pretix/base/banlist.py
+++ b/src/pretix/base/banlist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/cache.py b/src/pretix/base/cache.py
index e2702628c..d1829b411 100644
--- a/src/pretix/base/cache.py
+++ b/src/pretix/base/cache.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/channels.py b/src/pretix/base/channels.py
index c9ad7cf38..6f6bcab2d 100644
--- a/src/pretix/base/channels.py
+++ b/src/pretix/base/channels.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/context.py b/src/pretix/base/context.py
index ce1addb1f..475dfd4f1 100644
--- a/src/pretix/base/context.py
+++ b/src/pretix/base/context.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/customersso/__init__.py b/src/pretix/base/customersso/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/customersso/__init__.py
+++ b/src/pretix/base/customersso/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/customersso/oidc.py b/src/pretix/base/customersso/oidc.py
index 3e20d0ffd..b093c0125 100644
--- a/src/pretix/base/customersso/oidc.py
+++ b/src/pretix/base/customersso/oidc.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/datasync/__init__.py b/src/pretix/base/datasync/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/datasync/__init__.py
+++ b/src/pretix/base/datasync/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/datasync/datasync.py b/src/pretix/base/datasync/datasync.py
index a953be317..cb5bf01b3 100644
--- a/src/pretix/base/datasync/datasync.py
+++ b/src/pretix/base/datasync/datasync.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -106,7 +106,7 @@ class OutboundSyncProvider:
return str(cls.identifier)
@classmethod
- def enqueue_order(cls, order, triggered_by, not_before=None):
+ def enqueue_order(cls, order, triggered_by, not_before=None, immediate=False):
"""
Adds an order to the sync queue. May only be called on derived classes which define an ``identifier`` attribute.
@@ -119,10 +119,14 @@ 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.')
- OrderSyncQueue.objects.update_or_create(
+ queue_item, created = OrderSyncQueue.objects.update_or_create(
order=order,
sync_provider=cls.identifier,
in_flight=False,
@@ -133,6 +137,10 @@ 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):
@@ -383,7 +391,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(
diff --git a/src/pretix/base/datasync/sourcefields.py b/src/pretix/base/datasync/sourcefields.py
index 816f9d5cb..156145cb8 100644
--- a/src/pretix/base/datasync/sourcefields.py
+++ b/src/pretix/base/datasync/sourcefields.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/datasync/utils.py b/src/pretix/base/datasync/utils.py
index 05aab054a..ecfd948c5 100644
--- a/src/pretix/base/datasync/utils.py
+++ b/src/pretix/base/datasync/utils.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/decimal.py b/src/pretix/base/decimal.py
index 1d8a747f0..a34215a8a 100644
--- a/src/pretix/base/decimal.py
+++ b/src/pretix/base/decimal.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/email.py b/src/pretix/base/email.py
index b17f5b266..e1efce0b0 100644
--- a/src/pretix/base/email.py
+++ b/src/pretix/base/email.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporter.py b/src/pretix/base/exporter.py
index fb85dc3ab..2a40dabc9 100644
--- a/src/pretix/base/exporter.py
+++ b/src/pretix/base/exporter.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -105,6 +105,18 @@ 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:
"""
diff --git a/src/pretix/base/exporters/__init__.py b/src/pretix/base/exporters/__init__.py
index 49c8b6437..4260f07fe 100644
--- a/src/pretix/base/exporters/__init__.py
+++ b/src/pretix/base/exporters/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/answers.py b/src/pretix/base/exporters/answers.py
index 521376fee..9eb3b9d13 100644
--- a/src/pretix/base/exporters/answers.py
+++ b/src/pretix/base/exporters/answers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/customers.py b/src/pretix/base/exporters/customers.py
index 642f8f18f..7aa748093 100644
--- a/src/pretix/base/exporters/customers.py
+++ b/src/pretix/base/exporters/customers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/dekodi.py b/src/pretix/base/exporters/dekodi.py
index 4f6e6a32a..d77efed11 100644
--- a/src/pretix/base/exporters/dekodi.py
+++ b/src/pretix/base/exporters/dekodi.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/events.py b/src/pretix/base/exporters/events.py
index bd27c36ea..a53e153d8 100644
--- a/src/pretix/base/exporters/events.py
+++ b/src/pretix/base/exporters/events.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/invoices.py b/src/pretix/base/exporters/invoices.py
index 0cc9b6903..8aa3dba22 100644
--- a/src/pretix/base/exporters/invoices.py
+++ b/src/pretix/base/exporters/invoices.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -125,6 +125,7 @@ class InvoiceExporter(InvoiceExporterMixin, BaseExporter):
identifier = 'invoices'
verbose_name = _('All invoices')
description = _('Download all invoices created by the system as a ZIP file of PDF files.')
+ repeatable_read = False
def render(self, form_data: dict, output_file=None):
qs = self.invoices_queryset(form_data).filter(shredded=False)
@@ -180,6 +181,7 @@ class InvoiceDataExporter(InvoiceExporterMixin, MultiSheetListExporter):
'includes two sheets, one with a line for every invoice, and one with a line for every position of '
'every invoice.')
featured = True
+ repeatable_read = False
@property
def additional_form_fields(self):
diff --git a/src/pretix/base/exporters/items.py b/src/pretix/base/exporters/items.py
index fdff516e4..fba449768 100644
--- a/src/pretix/base/exporters/items.py
+++ b/src/pretix/base/exporters/items.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/json.py b/src/pretix/base/exporters/json.py
index 4c80e0a63..5791a2fa4 100644
--- a/src/pretix/base/exporters/json.py
+++ b/src/pretix/base/exporters/json.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/mail.py b/src/pretix/base/exporters/mail.py
index b7f7716f9..36c32c53d 100644
--- a/src/pretix/base/exporters/mail.py
+++ b/src/pretix/base/exporters/mail.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/exporters/orderlist.py b/src/pretix/base/exporters/orderlist.py
index 77501780f..e7b51cd7b 100644
--- a/src/pretix/base/exporters/orderlist.py
+++ b/src/pretix/base/exporters/orderlist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -89,7 +89,8 @@ class OrderListExporter(MultiSheetListExporter):
description = gettext_lazy('Download a spreadsheet of all orders. The spreadsheet will include three sheets, one '
'with a line for every order, one with a line for every order position, and one with '
'a line for every additional fee charged in an order.')
- featured = False
+ featured = True
+ repeatable_read = False
@cached_property
def providers(self):
@@ -842,6 +843,7 @@ class TransactionListExporter(ListExporter):
description = gettext_lazy('Download a spreadsheet of all substantial changes to orders, i.e. all changes to '
'products, prices or tax rates. The information is only accurate for changes made with '
'pretix versions released after October 2021.')
+ repeatable_read = False
@cached_property
def providers(self):
@@ -1020,6 +1022,7 @@ class PaymentListExporter(ListExporter):
category = pgettext_lazy('export_category', 'Order data')
description = gettext_lazy('Download a spreadsheet of all payments or refunds of every order.')
featured = True
+ repeatable_read = False
@property
def additional_form_fields(self):
@@ -1159,7 +1162,7 @@ class QuotaListExporter(ListExporter):
yield headers
quotas = list(self.event.quotas.select_related('subevent'))
- qa = QuotaAvailability(full_results=True)
+ qa = QuotaAvailability(full_results=True, allow_repeatable_read=True)
qa.queue(*quotas)
qa.compute()
@@ -1200,6 +1203,7 @@ class GiftcardTransactionListExporter(OrganizerLevelExportMixin, ListExporter):
organizer_required_permission = 'can_manage_gift_cards'
category = pgettext_lazy('export_category', 'Gift cards')
description = gettext_lazy('Download a spreadsheet of all gift card transactions.')
+ repeatable_read = False
@property
def additional_form_fields(self):
@@ -1258,6 +1262,7 @@ class GiftcardRedemptionListExporter(ListExporter):
verbose_name = gettext_lazy('Gift card redemptions')
category = pgettext_lazy('export_category', 'Order data')
description = gettext_lazy('Download a spreadsheet of all payments or refunds that involve gift cards.')
+ repeatable_read = False
def iterate_list(self, form_data):
payments = OrderPayment.objects.filter(
diff --git a/src/pretix/base/exporters/reusablemedia.py b/src/pretix/base/exporters/reusablemedia.py
index f73f1913a..83182c2df 100644
--- a/src/pretix/base/exporters/reusablemedia.py
+++ b/src/pretix/base/exporters/reusablemedia.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -34,6 +34,7 @@ class ReusableMediaExporter(OrganizerLevelExportMixin, ListExporter):
verbose_name = _('Reusable media')
category = pgettext_lazy('export_category', 'Reusable media')
description = _('Download a spread sheet with the data of all reusable medias on your account.')
+ repeatable_read = False
def iterate_list(self, form_data):
media = ReusableMedium.objects.filter(
diff --git a/src/pretix/base/exporters/waitinglist.py b/src/pretix/base/exporters/waitinglist.py
index 1b1cf1faf..978c80e8c 100644
--- a/src/pretix/base/exporters/waitinglist.py
+++ b/src/pretix/base/exporters/waitinglist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -41,6 +41,7 @@ class WaitingListExporter(ListExporter):
verbose_name = _('Waiting list')
category = pgettext_lazy('export_category', 'Waiting list')
description = _('Download a spread sheet with all your waiting list data.')
+ repeatable_read = False
# map selected status to label and queryset-filter
status_filters = [
diff --git a/src/pretix/base/forms/__init__.py b/src/pretix/base/forms/__init__.py
index 1f733dd0b..09f65259a 100644
--- a/src/pretix/base/forms/__init__.py
+++ b/src/pretix/base/forms/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/forms/auth.py b/src/pretix/base/forms/auth.py
index 4fc801c4f..dd44bb9a6 100644
--- a/src/pretix/base/forms/auth.py
+++ b/src/pretix/base/forms/auth.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/forms/questions.py b/src/pretix/base/forms/questions.py
index be8811d34..bb56ceb9c 100644
--- a/src/pretix/base/forms/questions.py
+++ b/src/pretix/base/forms/questions.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -77,7 +77,9 @@ from pretix.base.forms.widgets import (
from pretix.base.i18n import (
get_babel_locale, get_language_without_region, language,
)
-from pretix.base.invoicing.transmission import get_transmission_types
+from pretix.base.invoicing.transmission import (
+ get_transmission_types, transmission_types,
+)
from pretix.base.models import InvoiceAddress, Item, Question, QuestionOption
from pretix.base.models.tax import ask_for_vat_id
from pretix.base.services.tax import (
@@ -1142,9 +1144,11 @@ class BaseInvoiceAddressForm(forms.ModelForm):
if (not kwargs.get('instance') or not kwargs['instance'].country) and not kwargs["initial"].get("country"):
kwargs['initial']['country'] = guess_country_from_request(self.request, self.event)
- if kwargs.get('instance'):
- kwargs['initial'].update(kwargs['instance'].transmission_info or {})
- kwargs['initial']['transmission_type'] = kwargs['instance'].transmission_type
+ if kwargs.get('instance') and kwargs['instance'].transmission_type:
+ ttype, meta = transmission_types.get(identifier=kwargs['instance'].transmission_type)
+ if ttype:
+ kwargs['initial'].update(ttype.transmission_info_to_form_data(kwargs['instance'].transmission_info or {}))
+ kwargs['initial']['transmission_type'] = ttype.identifier
super().__init__(*args, **kwargs)
@@ -1394,9 +1398,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
raise ValidationError({r: _("This field is required for the selected type of invoice transmission.")})
self.instance.transmission_type = transmission_type.identifier
- self.instance.transmission_info = {
- k: data.get(k) for k in transmission_type.invoice_address_form_fields
- }
+ self.instance.transmission_info = transmission_type.form_data_to_transmission_info(data)
elif transmission_type.exclusive:
if transmission_type.is_available(self.event, data.get("country"), data.get("is_business")):
raise ValidationError({
diff --git a/src/pretix/base/forms/user.py b/src/pretix/base/forms/user.py
index e52bc51a4..10a904322 100644
--- a/src/pretix/base/forms/user.py
+++ b/src/pretix/base/forms/user.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/forms/validators.py b/src/pretix/base/forms/validators.py
index 35f7323ba..5a420b93e 100644
--- a/src/pretix/base/forms/validators.py
+++ b/src/pretix/base/forms/validators.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/forms/widgets.py b/src/pretix/base/forms/widgets.py
index 69620b201..2acf7dd53 100644
--- a/src/pretix/base/forms/widgets.py
+++ b/src/pretix/base/forms/widgets.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/i18n.py b/src/pretix/base/i18n.py
index ba7186ba0..7c510aa5d 100644
--- a/src/pretix/base/i18n.py
+++ b/src/pretix/base/i18n.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/invoice.py b/src/pretix/base/invoice.py
index 5efbee054..090b167c5 100644
--- a/src/pretix/base/invoice.py
+++ b/src/pretix/base/invoice.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/invoicing/__init__.py b/src/pretix/base/invoicing/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/invoicing/__init__.py
+++ b/src/pretix/base/invoicing/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/invoicing/email.py b/src/pretix/base/invoicing/email.py
index 97d47d96f..d3064af77 100644
--- a/src/pretix/base/invoicing/email.py
+++ b/src/pretix/base/invoicing/email.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -77,7 +77,7 @@ class EmailTransmissionType(TransmissionType):
}
def form_data_to_transmission_info(self, form_data: dict) -> dict:
- if form_data.get("transmission_email_other") and form_data.get("transmission_email_address"):
+ if form_data.get("is_business") and form_data.get("transmission_email_other") and form_data.get("transmission_email_address"):
return {
"transmission_email_address": form_data["transmission_email_address"],
}
diff --git a/src/pretix/base/invoicing/national.py b/src/pretix/base/invoicing/national.py
index b8c71fa55..47601145f 100644
--- a/src/pretix/base/invoicing/national.py
+++ b/src/pretix/base/invoicing/national.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/invoicing/pdf.py b/src/pretix/base/invoicing/pdf.py
index a6cbea7ea..2f2f36ed5 100644
--- a/src/pretix/base/invoicing/pdf.py
+++ b/src/pretix/base/invoicing/pdf.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -19,6 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
+import datetime
import logging
import math
import re
@@ -526,6 +527,20 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
textobject.textLine(self._normalize(self._upper(pgettext('invoice', 'Event'))))
canvas.drawText(textobject)
+ def _date_range_in_header(self):
+ if self.invoice.event.has_subevents or not self.invoice.event.settings.show_dates_on_frontpage:
+ return None, None
+ tz = self.invoice.event.timezone
+ show_end_date = (
+ self.invoice.event.settings.show_date_to and
+ self.invoice.event.date_to and
+ self.invoice.event.date_to.astimezone(tz).date() != self.invoice.event.date_from.astimezone(tz).date()
+ )
+ if show_end_date:
+ return self.invoice.event.date_from.astimezone(tz).date(), self.invoice.event.date_to.astimezone(tz).date()
+ else:
+ return self.invoice.event.date_from.astimezone(tz).date(), None
+
def _draw_event(self, canvas):
def shorten(txt):
txt = str(txt)
@@ -539,25 +554,17 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
p_size = p.wrap(self.event_width, self.event_height)
return txt
- if not self.invoice.event.has_subevents and self.invoice.event.settings.show_dates_on_frontpage:
- tz = self.invoice.event.timezone
- show_end_date = (
- self.invoice.event.settings.show_date_to and
- self.invoice.event.date_to and
- self.invoice.event.date_to.astimezone(tz).date() != self.invoice.event.date_from.astimezone(tz).date()
+ d_from, d_to = self._date_range_in_header()
+ if d_from and d_to:
+ p_str = (
+ shorten(self.invoice.event.name) + '\n' +
+ pgettext('invoice', '{from_date}\nuntil {to_date}').format(
+ from_date=date_format(d_from, "DATE_FORMAT"),
+ to_date=date_format(d_to, "DATE_FORMAT"),
+ )
)
- if show_end_date:
- p_str = (
- shorten(self.invoice.event.name) + '\n' +
- pgettext('invoice', '{from_date}\nuntil {to_date}').format(
- from_date=self.invoice.event.get_date_from_display(show_times=False),
- to_date=self.invoice.event.get_date_to_display(show_times=False)
- )
- )
- else:
- p_str = (
- shorten(self.invoice.event.name) + '\n' + self.invoice.event.get_date_from_display(show_times=False)
- )
+ elif d_from:
+ p_str = shorten(self.invoice.event.name) + '\n' + date_format(d_from, "DATE_FORMAT")
else:
p_str = shorten(self.invoice.event.name)
@@ -685,7 +692,14 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
return story
def _get_story(self, doc):
- has_taxes = any(il.tax_value for il in self.invoice.lines.all()) or self.invoice.reverse_charge
+ all_lines = list(self.invoice.lines.all())
+ has_taxes = any(il.tax_value for il in all_lines) or self.invoice.reverse_charge
+ header_dates = self._date_range_in_header()
+ tz = self.invoice.event.timezone
+ has_multiple_service_dates = len(set(
+ (il.period_start, il.period_end) for il in all_lines
+ )) > 1
+ request_show_service_date = False
story = [
NextPageTemplate('FirstPage'),
@@ -729,15 +743,75 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
)]
def _group_key(line):
- return (line.description, line.tax_rate, line.tax_name, line.net_value, line.gross_value, line.subevent_id,
- line.event_date_from, line.event_date_to)
+ return (line.description, line.tax_rate, line.tax_name, line.net_value, line.gross_value, line.subevent,
+ line.period_start, line.period_end)
+
+ def day(dt: datetime.datetime) -> datetime.date:
+ if dt is None:
+ return None
+ return dt.astimezone(tz).date()
total = Decimal('0.00')
- for (description, tax_rate, tax_name, net_value, gross_value, *ignored), lines in addon_aware_groupby(
- self.invoice.lines.all(),
+ for (description, tax_rate, tax_name, net_value, gross_value, subevent, period_start, period_end), lines in addon_aware_groupby(
+ all_lines,
key=_group_key,
is_addon=lambda l: l.description.startswith(" +"),
):
+ # Try to be clever and figure out when organizers would want to show the period. This heuristic is
+ # not perfect and the only "fully correct" way would be to include the period on every line always,
+ # however this will cause confusion (a) due to useless repetition of the same date all over the invoice
+ # (b) due to not respecting the show_date_to setting of events in cases where we could have respected it.
+ # Still, we want to show the date explicitly if its different to the event or invoice date.
+ period_start_day = day(period_start)
+ period_end_day = day(period_end)
+ if period_start and period_end and period_end_day != period_start_day:
+ # It's a multi-day period, such as the validity of the ticket or an event date period
+
+ if period_start_day == header_dates[0] and period_end_day == header_dates[1]:
+ # This is the exact event period we already printed in the header, no need to repeat it.
+ period_line = ""
+
+ elif (self.event.has_subevents and subevent and day(subevent.date_from) == period_start_day and
+ day(subevent.date_to) == period_end_day):
+ # For subevents, build_invoice already includes the date in the description in the event-default format.
+ period_line = ""
+
+ else:
+ period_line = f"{date_format(period_start_day, 'SHORT_DATE_FORMAT')} – {date_format(period_end_day, 'SHORT_DATE_FORMAT')}"
+
+ elif period_start or period_end:
+ # It's a single-day period
+
+ delivery_day = period_end_day or period_start_day
+ if delivery_day in header_dates:
+ # This is the event date we already printed in the header, no need to repeat it.
+ period_line = ""
+
+ elif self.event.has_subevents and subevent and delivery_day in (day(subevent.date_from), day(subevent.date_to)):
+ # For subevents, build_invoice already includes the date in the description in the event-default format.
+ period_line = ""
+
+ elif (delivery_day == self.invoice.date) and header_dates[0] is None:
+ # This is a shop that doesn't show the date of the event in the header, and the period is the invoice
+ # date. We assume that this is an 'everything is executed immediately' situation and do not want to
+ # confuse with showing additional dates on the invoice. This is the case that is not guaranteed to be
+ # correct in all cases and might need to change in the future. If customers have legal concerns, a
+ # quick fix is including a sentence like "Delivery date is the invoice date unless otherwise indicated:"
+ # in a custom text on the invoice.
+ period_line = ""
+
+ else:
+ period_line = date_format(delivery_day, 'SHORT_DATE_FORMAT')
+ else:
+ # No period known
+ period_line = ""
+
+ if not has_multiple_service_dates and period_line:
+ # Group together at the end of the invoice
+ request_show_service_date = period_line
+ elif period_line:
+ description += "\n" + period_line
+
lines = list(lines)
if has_taxes:
if len(lines) > 1:
@@ -746,6 +820,7 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
gross_price=money_filter(gross_value, self.invoice.event.currency),
)
description = description + "\n" + single_price_line
+
tdata.append((
FontFallbackParagraph(
self._clean_text(description, tags=['br']),
@@ -850,6 +925,12 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
story.append(Spacer(1, 10 * mm))
+ if request_show_service_date:
+ story.append(FontFallbackParagraph(
+ self._normalize(pgettext('invoice', 'Invoice period: {daterange}').format(daterange=request_show_service_date)),
+ self.stylesheet['Normal']
+ ))
+
if self.invoice.payment_provider_text:
story.append(FontFallbackParagraph(
self._normalize(self.invoice.payment_provider_text),
diff --git a/src/pretix/base/invoicing/peppol.py b/src/pretix/base/invoicing/peppol.py
index b31b3e645..c8a28752a 100644
--- a/src/pretix/base/invoicing/peppol.py
+++ b/src/pretix/base/invoicing/peppol.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/invoicing/transmission.py b/src/pretix/base/invoicing/transmission.py
index 584a056e5..6b7d39831 100644
--- a/src/pretix/base/invoicing/transmission.py
+++ b/src/pretix/base/invoicing/transmission.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -99,7 +99,9 @@ class TransmissionType:
return {}
def form_data_to_transmission_info(self, form_data: dict) -> dict:
- return form_data
+ return {
+ k: form_data.get(k) for k in self.invoice_address_form_fields
+ }
def transmission_info_to_form_data(self, transmission_info: dict) -> dict:
return transmission_info
diff --git a/src/pretix/base/logentrytype_registry.py b/src/pretix/base/logentrytype_registry.py
index 696ff24b6..71576d3f3 100644
--- a/src/pretix/base/logentrytype_registry.py
+++ b/src/pretix/base/logentrytype_registry.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/logentrytypes.py b/src/pretix/base/logentrytypes.py
index 32c464d5a..449b1ac06 100644
--- a/src/pretix/base/logentrytypes.py
+++ b/src/pretix/base/logentrytypes.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/__init__.py b/src/pretix/base/management/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/management/__init__.py
+++ b/src/pretix/base/management/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/__init__.py b/src/pretix/base/management/commands/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/management/commands/__init__.py
+++ b/src/pretix/base/management/commands/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/_migrations.py b/src/pretix/base/management/commands/_migrations.py
index 521525be1..b631db5df 100644
--- a/src/pretix/base/management/commands/_migrations.py
+++ b/src/pretix/base/management/commands/_migrations.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/check_order_transactions.py b/src/pretix/base/management/commands/check_order_transactions.py
index d059d001e..d3d6eeb8c 100644
--- a/src/pretix/base/management/commands/check_order_transactions.py
+++ b/src/pretix/base/management/commands/check_order_transactions.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/create_order_transactions.py b/src/pretix/base/management/commands/create_order_transactions.py
index ed65cca9f..55ffac2ff 100644
--- a/src/pretix/base/management/commands/create_order_transactions.py
+++ b/src/pretix/base/management/commands/create_order_transactions.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/export.py b/src/pretix/base/management/commands/export.py
index a398413ce..74c578ece 100644
--- a/src/pretix/base/management/commands/export.py
+++ b/src/pretix/base/management/commands/export.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/makemessages.py b/src/pretix/base/management/commands/makemessages.py
index bcbc67389..ed040813a 100644
--- a/src/pretix/base/management/commands/makemessages.py
+++ b/src/pretix/base/management/commands/makemessages.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/makemigrations.py b/src/pretix/base/management/commands/makemigrations.py
index 5a3bb65f0..7b88011fb 100644
--- a/src/pretix/base/management/commands/makemigrations.py
+++ b/src/pretix/base/management/commands/makemigrations.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/migrate.py b/src/pretix/base/management/commands/migrate.py
index 799696647..f027d1573 100644
--- a/src/pretix/base/management/commands/migrate.py
+++ b/src/pretix/base/management/commands/migrate.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/rebuild.py b/src/pretix/base/management/commands/rebuild.py
index 3161dc69b..839103f09 100644
--- a/src/pretix/base/management/commands/rebuild.py
+++ b/src/pretix/base/management/commands/rebuild.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/runperiodic.py b/src/pretix/base/management/commands/runperiodic.py
index 639b9b69b..b3e99ab9b 100644
--- a/src/pretix/base/management/commands/runperiodic.py
+++ b/src/pretix/base/management/commands/runperiodic.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/management/commands/shell_scoped.py b/src/pretix/base/management/commands/shell_scoped.py
index d5b67f90e..3438b3bb5 100644
--- a/src/pretix/base/management/commands/shell_scoped.py
+++ b/src/pretix/base/management/commands/shell_scoped.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/media.py b/src/pretix/base/media.py
index 0808e6869..47a1be987 100644
--- a/src/pretix/base/media.py
+++ b/src/pretix/base/media.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/metrics.py b/src/pretix/base/metrics.py
index c7db66f31..f0d024f8d 100755
--- a/src/pretix/base/metrics.py
+++ b/src/pretix/base/metrics.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/middleware.py b/src/pretix/base/middleware.py
index 82132665c..7e326d90f 100644
--- a/src/pretix/base/middleware.py
+++ b/src/pretix/base/middleware.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/migrations/0289_invoiceline_period.py b/src/pretix/base/migrations/0289_invoiceline_period.py
new file mode 100644
index 000000000..56f68b8b3
--- /dev/null
+++ b/src/pretix/base/migrations/0289_invoiceline_period.py
@@ -0,0 +1,78 @@
+# Generated by Django 4.2.17 on 2025-09-08 08:14
+from django.core.cache import cache
+from django.db import migrations
+
+
+def set_invoice_period(apps, schema_editor):
+ EventSettingsStore = apps.get_model("pretixbase", "Event_SettingsStore")
+ ev_seen = set()
+ insert_queue = []
+ flush_queue = []
+
+ def store():
+ EventSettingsStore.objects.bulk_create(
+ insert_queue,
+ update_conflicts=True,
+ update_fields=["value"],
+ unique_fields=["object", "key"],
+ )
+ cache.delete_many(flush_queue)
+ flush_queue.clear()
+ insert_queue.clear()
+
+ # Existing events that use pretix-zugferd and have explicitly disabled delivery dates
+ for setting in EventSettingsStore.objects.filter(key="zugferd_include_delivery_date", value="False"):
+ flush_queue.append("hierarkey_{}_{}".format("event", setting.object_id))
+ insert_queue.append(
+ EventSettingsStore(
+ object_id=setting.object_id,
+ key="invoice_period",
+ value="invoice_date",
+ )
+ )
+ ev_seen.add(setting.object_id)
+
+ if len(insert_queue) > 1000:
+ store()
+
+ # Existing events that previously hid their date on invoices
+ for setting in EventSettingsStore.objects.filter(key="show_dates_on_frontpage", value="False"):
+ if setting.object_id in ev_seen:
+ continue
+
+ flush_queue.append("hierarkey_{}_{}".format("event", setting.object_id))
+ insert_queue.append(
+ EventSettingsStore(
+ object_id=setting.object_id,
+ key="invoice_period",
+ value="auto_no_event",
+ )
+ )
+
+ if len(insert_queue) > 1000:
+ store()
+
+ store()
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("pretixbase", "0288_invoice_transmission"),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name="invoiceline",
+ old_name="event_date_to",
+ new_name="period_end",
+ ),
+ migrations.RenameField(
+ model_name="invoiceline",
+ old_name="event_date_from",
+ new_name="period_start",
+ ),
+ migrations.RunPython(
+ set_invoice_period,
+ migrations.RunPython.noop,
+ )
+ ]
diff --git a/src/pretix/base/migrations/0290_invoice_plugin_data.py b/src/pretix/base/migrations/0290_invoice_plugin_data.py
new file mode 100644
index 000000000..ca0f9d4e1
--- /dev/null
+++ b/src/pretix/base/migrations/0290_invoice_plugin_data.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.17 on 2025-09-09 09:55
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("pretixbase", "0289_invoiceline_period"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="invoice",
+ name="plugin_data",
+ field=models.JSONField(default=dict),
+ ),
+ ]
diff --git a/src/pretix/base/migrations/0291_alter_logentry_object_id.py b/src/pretix/base/migrations/0291_alter_logentry_object_id.py
new file mode 100644
index 000000000..6be090cb8
--- /dev/null
+++ b/src/pretix/base/migrations/0291_alter_logentry_object_id.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.16 on 2025-10-06 16:42
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("pretixbase", "0290_invoice_plugin_data"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="logentry",
+ name="object_id",
+ field=models.PositiveBigIntegerField(db_index=True),
+ ),
+ ]
diff --git a/src/pretix/base/migrations/0292_giftcard_customer.py b/src/pretix/base/migrations/0292_giftcard_customer.py
new file mode 100644
index 000000000..5ee6b7dd4
--- /dev/null
+++ b/src/pretix/base/migrations/0292_giftcard_customer.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.19 on 2025-05-19 11:06
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('pretixbase', '0291_alter_logentry_object_id'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='giftcard',
+ name='customer',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='customer_gift_cards', to='pretixbase.customer'),
+ ),
+ ]
diff --git a/src/pretix/base/modelimport.py b/src/pretix/base/modelimport.py
index f700c349f..43b956e1a 100644
--- a/src/pretix/base/modelimport.py
+++ b/src/pretix/base/modelimport.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/modelimport_orders.py b/src/pretix/base/modelimport_orders.py
index f87a24f2d..144cdf613 100644
--- a/src/pretix/base/modelimport_orders.py
+++ b/src/pretix/base/modelimport_orders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -175,7 +175,7 @@ class Variation(ImportColumn):
if value:
matches = [
p for p in self.items
- if str(p.pk) == value or any((v and v == value) for v in i18n_flat(p.value)) and p.item_id == previous_values['item'].pk
+ if (str(p.pk) == value or any((v and v == value) for v in i18n_flat(p.value))) and p.item_id == previous_values['item'].pk
]
if len(matches) == 0:
raise ValidationError(_("No matching variation was found."))
diff --git a/src/pretix/base/modelimport_vouchers.py b/src/pretix/base/modelimport_vouchers.py
index c48c06fcd..a9e2199ff 100644
--- a/src/pretix/base/modelimport_vouchers.py
+++ b/src/pretix/base/modelimport_vouchers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/__init__.py b/src/pretix/base/models/__init__.py
index d3e68f6bd..944737501 100644
--- a/src/pretix/base/models/__init__.py
+++ b/src/pretix/base/models/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/_transactions.py b/src/pretix/base/models/_transactions.py
index 5fecab2b2..1aaf2919b 100644
--- a/src/pretix/base/models/_transactions.py
+++ b/src/pretix/base/models/_transactions.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/auth.py b/src/pretix/base/models/auth.py
index 27e0ee696..31871dadb 100644
--- a/src/pretix/base/models/auth.py
+++ b/src/pretix/base/models/auth.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/base.py b/src/pretix/base/models/base.py
index c1c1fb553..d8154aa8f 100644
--- a/src/pretix/base/models/base.py
+++ b/src/pretix/base/models/base.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/checkin.py b/src/pretix/base/models/checkin.py
index e9e160d4b..0926cedee 100644
--- a/src/pretix/base/models/checkin.py
+++ b/src/pretix/base/models/checkin.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/currencies.py b/src/pretix/base/models/currencies.py
index b8f1c79c9..dd6c6775b 100644
--- a/src/pretix/base/models/currencies.py
+++ b/src/pretix/base/models/currencies.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/customers.py b/src/pretix/base/models/customers.py
index 019f6fa87..942ae5918 100644
--- a/src/pretix/base/models/customers.py
+++ b/src/pretix/base/models/customers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -19,6 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
+from decimal import Decimal
+
import pycountry
from django.conf import settings
from django.contrib.auth.hashers import (
@@ -27,7 +29,11 @@ from django.contrib.auth.hashers import (
from django.core.validators import RegexValidator, URLValidator
from django.db import models
from django.db.models import F, Q
+from django.db.models.aggregates import Sum
+from django.db.models.expressions import OuterRef, Subquery
+from django.db.models.functions.comparison import Coalesce
from django.utils.crypto import get_random_string, salted_hmac
+from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django_scopes import ScopedManager, scopes_disabled
from i18nfield.fields import I18nCharField
@@ -36,6 +42,7 @@ from phonenumber_field.modelfields import PhoneNumberField
from pretix.base.banlist import banned
from pretix.base.models.base import LoggedModel
from pretix.base.models.fields import MultiStringField
+from pretix.base.models.giftcards import GiftCardTransaction
from pretix.base.models.organizer import Organizer
from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.helpers.countries import FastCountryField
@@ -288,6 +295,19 @@ class Customer(LoggedModel):
organizer=self.organizer,
)
+ def usable_gift_cards(self, used_cards=[]):
+ s = GiftCardTransaction.objects.filter(
+ card=OuterRef('pk')
+ ).order_by().values('card').annotate(s=Sum('value')).values('s')
+ qs = self.customer_gift_cards.annotate(
+ cached_value=Coalesce(Subquery(s), Decimal('0.00')),
+ )
+ ne_qs = qs.filter(
+ Q(expires__isnull=True) | Q(expires__gte=now()),
+ )
+ ex_qs = ne_qs.exclude(id__in=used_cards)
+ return ex_qs.filter(cached_value__gt=0)
+
class AttendeeProfile(models.Model):
customer = models.ForeignKey(
diff --git a/src/pretix/base/models/datasync.py b/src/pretix/base/models/datasync.py
index 065832403..e6b2bbd22 100644
--- a/src/pretix/base/models/datasync.py
+++ b/src/pretix/base/models/datasync.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/devices.py b/src/pretix/base/models/devices.py
index 71c614159..c94cf6827 100644
--- a/src/pretix/base/models/devices.py
+++ b/src/pretix/base/models/devices.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/discount.py b/src/pretix/base/models/discount.py
index dc99e4bda..9c09edc65 100644
--- a/src/pretix/base/models/discount.py
+++ b/src/pretix/base/models/discount.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py
index 5a1cdd4b2..c96ee870d 100644
--- a/src/pretix/base/models/event.py
+++ b/src/pretix/base/models/event.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -1639,20 +1639,16 @@ class SubEvent(EventMixin, LoggedModel):
@cached_property
def item_overrides(self):
- from .items import SubEventItem
-
return {
si.item_id: si
- for si in SubEventItem.objects.filter(subevent=self)
+ for si in self.subeventitem_set.all()
}
@cached_property
def var_overrides(self):
- from .items import SubEventItemVariation
-
return {
si.variation_id: si
- for si in SubEventItemVariation.objects.filter(subevent=self)
+ for si in self.subeventitemvariation_set.all()
}
@property
diff --git a/src/pretix/base/models/exports.py b/src/pretix/base/models/exports.py
index 6104ff2b1..a539f371b 100644
--- a/src/pretix/base/models/exports.py
+++ b/src/pretix/base/models/exports.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/fields.py b/src/pretix/base/models/fields.py
index 218a7c668..73ad7badf 100644
--- a/src/pretix/base/models/fields.py
+++ b/src/pretix/base/models/fields.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/giftcards.py b/src/pretix/base/models/giftcards.py
index 905469737..409bf4a1c 100644
--- a/src/pretix/base/models/giftcards.py
+++ b/src/pretix/base/models/giftcards.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -80,6 +80,13 @@ class GiftCard(LoggedModel):
null=True, blank=True,
verbose_name=_('Owned by ticket holder')
)
+ customer = models.ForeignKey(
+ 'Customer',
+ related_name='customer_gift_cards',
+ on_delete=models.PROTECT,
+ null=True, blank=True,
+ verbose_name=_('Owned by customer account')
+ )
issuance = models.DateTimeField(
auto_now_add=True,
)
@@ -195,20 +202,21 @@ class GiftCardTransaction(models.Model):
return response
if self.order_id:
- if not self.text:
- if not customer_facing:
- return format_html(
- '{}',
- reverse(
- "control:event.order",
- kwargs={
- "event": self.order.event.slug,
- "organizer": self.order.event.organizer.slug,
- "code": self.order.code,
- }
- ),
- self.order.full_code
- )
+ if not customer_facing:
+ return format_html(
+ '{} {}',
+ reverse(
+ "control:event.order",
+ kwargs={
+ "event": self.order.event.slug,
+ "organizer": self.order.event.organizer.slug,
+ "code": self.order.code,
+ }
+ ),
+ self.order.full_code,
+ self.text or "",
+ )
+ elif not self.text:
return self.order.full_code
else:
return self.text
diff --git a/src/pretix/base/models/invoices.py b/src/pretix/base/models/invoices.py
index 0dfde5d57..602e062d8 100644
--- a/src/pretix/base/models/invoices.py
+++ b/src/pretix/base/models/invoices.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -33,6 +33,7 @@
# License for the specific language governing permissions and limitations under the License.
import string
+import warnings
from decimal import Decimal
import pycountry
@@ -201,6 +202,7 @@ class Invoice(models.Model):
transmission_info = models.JSONField(null=True, blank=True)
file = models.FileField(null=True, blank=True, upload_to=invoice_filename, max_length=255)
+ plugin_data = models.JSONField(default=dict)
objects = ScopedManager(organizer='event__organizer')
@@ -404,10 +406,10 @@ class InvoiceLine(models.Model):
:type tax_name: str
:param subevent: The subevent this line refers to
:type subevent: SubEvent
- :param event_date_from: Event date of the (sub)event at the time the invoice was created
- :type event_date_from: datetime
- :param event_date_to: Event end date of the (sub)event at the time the invoice was created
- :type event_date_to: datetime
+ :param period_start: Start if service period invoiced
+ :type period_start: datetime
+ :param period_end: End of service period invoiced
+ :type period_end: datetime
:param event_location: Event location of the (sub)event at the time the invoice was created
:type event_location: str
:param item: The item this line refers to
@@ -426,8 +428,8 @@ class InvoiceLine(models.Model):
tax_name = models.CharField(max_length=190)
tax_code = models.CharField(max_length=190, null=True, blank=True)
subevent = models.ForeignKey('SubEvent', null=True, blank=True, on_delete=models.PROTECT)
- event_date_from = models.DateTimeField(null=True)
- event_date_to = models.DateTimeField(null=True)
+ period_start = models.DateTimeField(null=True)
+ period_end = models.DateTimeField(null=True)
event_location = models.TextField(null=True, blank=True)
item = models.ForeignKey('Item', null=True, blank=True, on_delete=models.PROTECT)
variation = models.ForeignKey('ItemVariation', null=True, blank=True, on_delete=models.PROTECT)
@@ -444,3 +446,35 @@ class InvoiceLine(models.Model):
def __str__(self):
return 'Line {} of invoice {}'.format(self.position, self.invoice)
+
+ @property
+ def event_date_from(self):
+ warnings.warn(
+ 'InvoiceLine.event_date_from is deprecated, use period_start instead,',
+ category=DeprecationWarning,
+ )
+ return self.period_start
+
+ @event_date_from.setter
+ def event_date_from(self, value):
+ warnings.warn(
+ 'InvoiceLine.event_date_from is deprecated, use period_start instead,',
+ category=DeprecationWarning,
+ )
+ self.period_start = value
+
+ @property
+ def event_date_to(self):
+ warnings.warn(
+ 'InvoiceLine.event_date_to is deprecated, use period_end instead,',
+ category=DeprecationWarning,
+ )
+ return self.period_end
+
+ @event_date_to.setter
+ def event_date_to(self, value):
+ warnings.warn(
+ 'InvoiceLine.event_date_to is deprecated, use period_end instead,',
+ category=DeprecationWarning,
+ )
+ self.period_to = value
diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py
index c13d4f859..7e42f2cb7 100644
--- a/src/pretix/base/models/items.py
+++ b/src/pretix/base/models/items.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/log.py b/src/pretix/base/models/log.py
index 368bd99f1..2ccf5c20e 100644
--- a/src/pretix/base/models/log.py
+++ b/src/pretix/base/models/log.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -66,7 +66,7 @@ class LogEntry(models.Model):
:type data: str
"""
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
- object_id = models.PositiveIntegerField(db_index=True)
+ object_id = models.PositiveBigIntegerField(db_index=True)
content_object = GenericForeignKey('content_type', 'object_id')
datetime = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey('User', null=True, blank=True, on_delete=models.PROTECT)
diff --git a/src/pretix/base/models/media.py b/src/pretix/base/models/media.py
index eedf71390..be8a0af9d 100644
--- a/src/pretix/base/models/media.py
+++ b/src/pretix/base/models/media.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/memberships.py b/src/pretix/base/models/memberships.py
index 14640b2cf..f2d5fd5cb 100644
--- a/src/pretix/base/models/memberships.py
+++ b/src/pretix/base/models/memberships.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/notifications.py b/src/pretix/base/models/notifications.py
index 6b23c9260..5af7c4148 100644
--- a/src/pretix/base/models/notifications.py
+++ b/src/pretix/base/models/notifications.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py
index f48e7dd63..adcb69bcc 100644
--- a/src/pretix/base/models/orders.py
+++ b/src/pretix/base/models/orders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -1840,6 +1840,10 @@ class OrderPayment(models.Model):
))
return False
+ if locked_instance.state == OrderPayment.PAYMENT_STATE_CANCELED:
+ # Never send mails when the payment was already canceled intentionally
+ send_mail = False
+
if isinstance(info, str):
locked_instance.info = info
elif info:
@@ -1855,6 +1859,10 @@ class OrderPayment(models.Model):
'data': log_data,
}, user=user, auth=auth)
+ if self.order.status in (Order.STATUS_PAID, Order.STATUS_CANCELED, Order.STATUS_EXPIRED):
+ # No reason to send mail, as the payment is no longer really expected
+ send_mail = False
+
if send_mail:
with language(self.order.locale, self.order.event.settings.region):
email_subject = self.order.event.settings.mail_subject_order_payment_failed
@@ -1961,14 +1969,20 @@ class OrderPayment(models.Model):
self.order.invoice_dirty
)
if gen_invoice:
- if invoices:
- last_i = self.order.invoices.filter(is_cancellation=False).last()
- if not last_i.canceled:
- generate_cancellation(last_i)
- invoice = generate_invoice(
- self.order,
- trigger_pdf=not send_mail or not self.order.event.settings.invoice_email_attachment
- )
+ try:
+ if invoices:
+ last_i = self.order.invoices.filter(is_cancellation=False).last()
+ if not last_i.canceled:
+ generate_cancellation(last_i)
+ invoice = generate_invoice(
+ self.order,
+ trigger_pdf=not send_mail or not self.order.event.settings.invoice_email_attachment
+ )
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ self.order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
transmit_invoice_task = invoice_transmission_separately(invoice)
transmit_invoice_mail = not transmit_invoice_task and self.order.event.settings.invoice_email_attachment and self.order.email
diff --git a/src/pretix/base/models/organizer.py b/src/pretix/base/models/organizer.py
index 757bf3457..71cc083f4 100644
--- a/src/pretix/base/models/organizer.py
+++ b/src/pretix/base/models/organizer.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/seating.py b/src/pretix/base/models/seating.py
index 372131d66..70ac0b892 100644
--- a/src/pretix/base/models/seating.py
+++ b/src/pretix/base/models/seating.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/tax.py b/src/pretix/base/models/tax.py
index 1058934cd..cab647049 100644
--- a/src/pretix/base/models/tax.py
+++ b/src/pretix/base/models/tax.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/vouchers.py b/src/pretix/base/models/vouchers.py
index 9dc8afe3d..a1531e987 100644
--- a/src/pretix/base/models/vouchers.py
+++ b/src/pretix/base/models/vouchers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/models/waitinglist.py b/src/pretix/base/models/waitinglist.py
index f7cf0ff8e..1eedd4ab3 100644
--- a/src/pretix/base/models/waitinglist.py
+++ b/src/pretix/base/models/waitinglist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/notifications.py b/src/pretix/base/notifications.py
index f4f661786..b95d48406 100644
--- a/src/pretix/base/notifications.py
+++ b/src/pretix/base/notifications.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py
index b73fecd1a..72f127770 100644
--- a/src/pretix/base/payment.py
+++ b/src/pretix/base/payment.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -38,6 +38,7 @@ import json
import logging
from collections import OrderedDict
from decimal import ROUND_HALF_UP, Decimal
+from functools import cached_property
from typing import Any, Dict, Union
from zoneinfo import ZoneInfo
@@ -57,8 +58,8 @@ from i18nfield.strings import LazyI18nString
from pretix.base.forms import I18nMarkdownTextarea, PlaceholderValidator
from pretix.base.models import (
- CartPosition, Event, GiftCard, InvoiceAddress, Order, OrderPayment,
- OrderRefund, Quota, TaxRule,
+ CartPosition, Customer, Event, GiftCard, InvoiceAddress, Order,
+ OrderPayment, OrderRefund, Quota, TaxRule,
)
from pretix.base.reldate import RelativeDateField, RelativeDateWrapper
from pretix.base.settings import SettingsSandbox
@@ -99,6 +100,7 @@ class PaymentProviderForm(Form):
class GiftCardPaymentForm(PaymentProviderForm):
def __init__(self, *args, **kwargs):
+ self.customer_gift_cards = kwargs.pop('customer_gift_cards') if 'customer_gift_cards' in kwargs else None
self.event = kwargs.pop('event')
self.testmode = kwargs.pop('testmode')
self.positions = kwargs.pop('positions')
@@ -1373,6 +1375,31 @@ class GiftCardPayment(BasePaymentProvider):
payment_form_class = GiftCardPaymentForm
payment_form_template_name = 'pretixcontrol/giftcards/checkout.html'
+ @cached_property
+ def customer_gift_cards(self):
+ if not self.request:
+ return None
+ if not self.used_cards:
+ self.used_cards = []
+ cs = None
+ if 'checkout' in self.request.resolver_match.url_name:
+ cs = cart_session(self.request)
+ customer = getattr(self.request, "customer", None)
+ if customer:
+ return customer.usable_gift_cards(self.used_cards)
+ elif cs and cs.get('customer_mode', 'guest') == 'login':
+ try:
+ customer = self.request.organizer.customers.get(pk=cs["customer"])
+ return customer.usable_gift_cards(self.used_cards)
+ except Customer.DoesNotExist:
+ return None
+
+ def payment_form_render(self, request: HttpRequest, total: Decimal, order: Order = None) -> str:
+ form = self.payment_form(request)
+ template = get_template(self.payment_form_template_name)
+ ctx = {'request': request, 'form': form, 'customer_gift_cards': form.customer_gift_cards, }
+ return template.render(ctx)
+
def payment_form(self, request: HttpRequest) -> Form:
# Unfortunately, in payment_form we do not know if we're in checkout
# or in an existing order. But we need to do the validation logic in the
@@ -1392,8 +1419,12 @@ class GiftCardPayment(BasePaymentProvider):
positions = order.positions.all()
testmode = order.testmode
+ self.request = request
+ self.used_cards = used_cards
+
form = self.payment_form_class(
event=self.event,
+ customer_gift_cards=self.customer_gift_cards,
used_cards=used_cards,
positions=positions,
testmode=testmode,
@@ -1627,6 +1658,7 @@ class GiftCardPayment(BasePaymentProvider):
order=refund.order,
refund=refund,
acceptor=self.event.organizer,
+ text=refund.comment,
)
refund.info_data = {
'gift_card': gc.pk,
diff --git a/src/pretix/base/pdf.py b/src/pretix/base/pdf.py
index 21414055b..ed00d9231 100644
--- a/src/pretix/base/pdf.py
+++ b/src/pretix/base/pdf.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/plugins.py b/src/pretix/base/plugins.py
index f26eb7747..4f32b6682 100644
--- a/src/pretix/base/plugins.py
+++ b/src/pretix/base/plugins.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -29,6 +29,7 @@ from django.apps import AppConfig, apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext_lazy as _
+from django_scopes import scope
from packaging.requirements import Requirement
PLUGIN_LEVEL_EVENT = 'event'
@@ -71,7 +72,8 @@ def get_all_plugins(*, event=None, organizer=None) -> List[type]:
continue
elif organizer and hasattr(app, 'is_available'):
if not event_fallback_used:
- event_fallback = organizer.events.first()
+ with scope(organizer=organizer):
+ event_fallback = organizer.events.first()
event_fallback_used = True
if not event_fallback or not app.is_available(event_fallback):
continue
diff --git a/src/pretix/base/reldate.py b/src/pretix/base/reldate.py
index 79d49b82f..3b67610d5 100644
--- a/src/pretix/base/reldate.py
+++ b/src/pretix/base/reldate.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/secretgenerators/__init__.py b/src/pretix/base/secretgenerators/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/secretgenerators/__init__.py
+++ b/src/pretix/base/secretgenerators/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/secretgenerators/pretix_sig1_pb2.py b/src/pretix/base/secretgenerators/pretix_sig1_pb2.py
index 4748a7e20..06b6a9059 100644
--- a/src/pretix/base/secretgenerators/pretix_sig1_pb2.py
+++ b/src/pretix/base/secretgenerators/pretix_sig1_pb2.py
@@ -2,8 +2,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/secrets.py b/src/pretix/base/secrets.py
index 32f64c21e..da253e531 100644
--- a/src/pretix/base/secrets.py
+++ b/src/pretix/base/secrets.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/__init__.py b/src/pretix/base/services/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/services/__init__.py
+++ b/src/pretix/base/services/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/auth.py b/src/pretix/base/services/auth.py
index b66447a80..0aae4abd9 100644
--- a/src/pretix/base/services/auth.py
+++ b/src/pretix/base/services/auth.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/cancelevent.py b/src/pretix/base/services/cancelevent.py
index 3f14c91dc..89d0d82b6 100644
--- a/src/pretix/base/services/cancelevent.py
+++ b/src/pretix/base/services/cancelevent.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -24,6 +24,7 @@ from decimal import Decimal
from django.db import transaction
from django.db.models import Count, Exists, IntegerField, OuterRef, Q, Subquery
+from django.utils.crypto import get_random_string
from django.utils.translation import gettext
from i18nfield.strings import LazyI18nString
@@ -41,6 +42,7 @@ from pretix.base.services.orders import (
)
from pretix.base.services.tasks import ProfiledEventTask
from pretix.base.services.tax import split_fee_for_taxes
+from pretix.base.templatetags.money import money_filter
from pretix.celery_app import app
from pretix.helpers import OF_SELF
from pretix.helpers.format import format_map
@@ -112,7 +114,7 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
manual_refund: bool=False, send: bool=False, send_subject: dict=None, send_message: dict=None,
send_waitinglist: bool=False, send_waitinglist_subject: dict={}, send_waitinglist_message: dict={},
user: int=None, refund_as_giftcard: bool=False, giftcard_expires=None, giftcard_conditions=None,
- subevents_from: str=None, subevents_to: str=None):
+ subevents_from: str=None, subevents_to: str=None, dry_run=False):
send_subject = LazyI18nString(send_subject)
send_message = LazyI18nString(send_message)
send_waitinglist_subject = LazyI18nString(send_waitinglist_subject)
@@ -161,32 +163,72 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
has_subevent=True, has_other_subevent=False, has_blocked=False
)
- for se in subevents:
- se.log_action(
- 'pretix.subevent.canceled', user=user,
- )
- se.active = False
- se.save(update_fields=['active'])
- se.log_action(
- 'pretix.subevent.changed', user=user, data={'active': False, '_source': 'cancel_event'}
- )
+ if not dry_run:
+ for se in subevents:
+ se.log_action(
+ 'pretix.subevent.canceled', user=user,
+ data={
+ "auto_refund": auto_refund,
+ "keep_fee_fixed": keep_fee_fixed,
+ "keep_fee_per_ticket": keep_fee_per_ticket,
+ "keep_fee_percentage": keep_fee_percentage,
+ "keep_fees": keep_fees,
+ "manual_refund": manual_refund,
+ "send": send,
+ "send_subject": send_subject,
+ "send_message": send_message,
+ "send_waitinglist": send_waitinglist,
+ "send_waitinglist_subject": send_waitinglist_subject,
+ "send_waitinglist_message": send_waitinglist_message,
+ "refund_as_giftcard": refund_as_giftcard,
+ "giftcard_expires": str(giftcard_expires),
+ "giftcard_conditions": giftcard_conditions,
+ }
+ )
+ se.active = False
+ se.save(update_fields=['active'])
+ se.log_action(
+ 'pretix.subevent.changed', user=user, data={'active': False, '_source': 'cancel_event'}
+ )
else:
subevents = None
subevent_ids = set()
orders_to_change = orders_to_cancel.filter(has_blocked=True)
orders_to_cancel = orders_to_cancel.filter(has_blocked=False)
- event.log_action(
- 'pretix.event.canceled', user=user,
- )
- for i in event.items.filter(active=True):
- i.active = False
- i.save(update_fields=['active'])
- i.log_action(
- 'pretix.event.item.changed', user=user, data={'active': False, '_source': 'cancel_event'}
+ if not dry_run:
+ event.log_action(
+ 'pretix.event.canceled', user=user,
+ data={
+ "auto_refund": auto_refund,
+ "keep_fee_fixed": keep_fee_fixed,
+ "keep_fee_per_ticket": keep_fee_per_ticket,
+ "keep_fee_percentage": keep_fee_percentage,
+ "keep_fees": keep_fees,
+ "manual_refund": manual_refund,
+ "send": send,
+ "send_subject": send_subject,
+ "send_message": send_message,
+ "send_waitinglist": send_waitinglist,
+ "send_waitinglist_subject": send_waitinglist_subject,
+ "send_waitinglist_message": send_waitinglist_message,
+ "refund_as_giftcard": refund_as_giftcard,
+ "giftcard_expires": str(giftcard_expires),
+ "giftcard_conditions": giftcard_conditions,
+ }
)
+
+ for i in event.items.filter(active=True):
+ i.active = False
+ i.save(update_fields=['active'])
+ i.log_action(
+ 'pretix.event.item.changed', user=user, data={'active': False, '_source': 'cancel_event'}
+ )
failed = 0
- total = orders_to_cancel.count() + orders_to_change.count()
+ refund_total = Decimal("0.00")
+ cancel_full_total = orders_to_cancel.count()
+ cancel_partial_total = orders_to_change.count()
+ total = cancel_full_total + cancel_partial_total
qs_wl = event.waitinglistentries.filter(voucher__isnull=True).select_related('subevent')
if subevents:
qs_wl = qs_wl.filter(subevent__in=subevents)
@@ -199,6 +241,7 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
)
for o in orders_to_cancel.only('id', 'total').iterator():
+ payment_refund_sum = o.payment_refund_sum # cache to avoid multiple computations
try:
fee = Decimal('0.00')
fee_sum = Decimal('0.00')
@@ -217,20 +260,24 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
for p in o.positions.all():
if p.addon_to_id is None:
fee += min(p.price, Decimal(keep_fee_per_ticket))
- fee = round_decimal(min(fee, o.payment_refund_sum), event.currency)
+ fee = round_decimal(min(fee, payment_refund_sum), event.currency)
- _cancel_order(o.pk, user, send_mail=False, cancellation_fee=fee, keep_fees=keep_fee_objects)
- refund_amount = o.payment_refund_sum
+ if dry_run:
+ refund_total += max(Decimal("0.00"), min(payment_refund_sum, o.total - fee))
+ else:
+ _cancel_order(o.pk, user, send_mail=False, cancellation_fee=fee, keep_fees=keep_fee_objects)
+ refund_amount = payment_refund_sum
+ refund_amount += refund_total
- try:
- if auto_refund or manual_refund:
- _try_auto_refund(o.pk, auto_refund=auto_refund, manual_refund=manual_refund, allow_partial=True,
- source=OrderRefund.REFUND_SOURCE_ADMIN, refund_as_giftcard=refund_as_giftcard,
- giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions,
- comment=gettext('Event canceled'))
- finally:
- if send:
- _send_mail(o, send_subject, send_message, subevent, refund_amount, user, o.positions.all())
+ try:
+ if auto_refund or manual_refund:
+ _try_auto_refund(o.pk, auto_refund=auto_refund, manual_refund=manual_refund, allow_partial=True,
+ source=OrderRefund.REFUND_SOURCE_ADMIN, refund_as_giftcard=refund_as_giftcard,
+ giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions,
+ comment=gettext('Event canceled'))
+ finally:
+ if send:
+ _send_mail(o, send_subject, send_message, subevent, refund_amount, user, o.positions.all())
counter += 1
if not self.request.called_directly and counter % max(10, total // 100) == 0:
@@ -247,12 +294,16 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
for o in orders_to_change.values_list('id', flat=True).iterator():
with transaction.atomic():
- o = event.orders.select_for_update(of=OF_SELF).get(pk=o)
+ if dry_run:
+ o = event.orders.get(pk=o)
+ else:
+ o = event.orders.select_for_update(of=OF_SELF).get(pk=o)
total = Decimal('0.00')
fee = Decimal('0.00')
positions = []
ocm = OrderChangeManager(o, user=user, notify=False)
+ payment_refund_sum = o.payment_refund_sum # cache to avoid multiple computations
for p in o.positions.all():
if (not event.has_subevents or p.subevent_id in subevent_ids) and not p.blocked:
total += p.price
@@ -267,7 +318,7 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
fee += Decimal(keep_fee_fixed)
if keep_fee_percentage:
fee += Decimal(keep_fee_percentage) / Decimal('100.00') * total
- fee = round_decimal(min(fee, o.payment_refund_sum), event.currency)
+ fee = round_decimal(min(fee, payment_refund_sum), event.currency)
if fee:
tax_rule_zero = TaxRule.zero()
if event.settings.tax_rule_cancellation == "default":
@@ -298,17 +349,21 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
)
ocm.add_fee(f)
- ocm.commit()
- refund_amount = o.payment_refund_sum - o.total
+ if dry_run:
+ refund_total += max(payment_refund_sum - (o.total + ocm._totaldiff), Decimal("0.00"))
+ else:
+ ocm.commit()
+ refund_amount = payment_refund_sum - o.total
+ refund_total += refund_amount
- if auto_refund or manual_refund:
- _try_auto_refund(o.pk, auto_refund=auto_refund, manual_refund=manual_refund, allow_partial=True,
- source=OrderRefund.REFUND_SOURCE_ADMIN, refund_as_giftcard=refund_as_giftcard,
- giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions,
- comment=gettext('Event canceled'))
+ if auto_refund or manual_refund:
+ _try_auto_refund(o.pk, auto_refund=auto_refund, manual_refund=manual_refund, allow_partial=True,
+ source=OrderRefund.REFUND_SOURCE_ADMIN, refund_as_giftcard=refund_as_giftcard,
+ giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions,
+ comment=gettext('Event canceled'))
- if send:
- _send_mail(o, send_subject, send_message, subevent, refund_amount, user, positions)
+ if send:
+ _send_mail(o, send_subject, send_message, subevent, refund_amount, user, positions)
counter += 1
if not self.request.called_directly and counter % max(10, total // 100) == 0:
@@ -319,7 +374,8 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
if send_waitinglist:
for wle in qs_wl:
- _send_wle_mail(wle, send_waitinglist_subject, send_waitinglist_message, wle.subevent)
+ if not dry_run:
+ _send_wle_mail(wle, send_waitinglist_subject, send_waitinglist_message, wle.subevent)
counter += 1
if not self.request.called_directly and counter % max(10, total // 100) == 0:
@@ -327,4 +383,30 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
state='PROGRESS',
meta={'value': round(counter / total * 100 if total else 0, 2)}
)
- return failed
+
+ confirmation_code = None
+ if dry_run and user and refund_total > Decimal('100.00'):
+ confirmation_code = get_random_string(8, allowed_chars="01234567890")
+ mail(
+ user.email,
+ subject=gettext('Bulk-refund confirmation'),
+ template='pretixbase/email/cancel_confirm.txt',
+ context={
+ "event": str(event),
+ "amount": money_filter(refund_total, event.currency),
+ "confirmation_code": confirmation_code,
+ },
+ locale=user.locale,
+ )
+
+ return {
+ "dry_run": dry_run,
+ "id": self.request.id,
+ "failed": failed,
+ "refund_total": refund_total,
+ "cancel_full_total": cancel_full_total,
+ "cancel_partial_total": cancel_partial_total,
+ "confirmation_code": confirmation_code,
+ "args": self.request.args,
+ "kwargs": self.request.kwargs,
+ }
diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py
index 3b256bd62..efffda374 100644
--- a/src/pretix/base/services/cart.py
+++ b/src/pretix/base/services/cart.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/checkin.py b/src/pretix/base/services/checkin.py
index 7c2e6237f..ecf4cf7a9 100644
--- a/src/pretix/base/services/checkin.py
+++ b/src/pretix/base/services/checkin.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/cleanup.py b/src/pretix/base/services/cleanup.py
index 9190b0ab2..6667b2c3f 100644
--- a/src/pretix/base/services/cleanup.py
+++ b/src/pretix/base/services/cleanup.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/cross_selling.py b/src/pretix/base/services/cross_selling.py
index fe48d1e01..0a234dd8b 100644
--- a/src/pretix/base/services/cross_selling.py
+++ b/src/pretix/base/services/cross_selling.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/currencies.py b/src/pretix/base/services/currencies.py
index ad0464c49..620f88b12 100644
--- a/src/pretix/base/services/currencies.py
+++ b/src/pretix/base/services/currencies.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/datasync.py b/src/pretix/base/services/datasync.py
index c4d48da7e..f98d7514e 100644
--- a/src/pretix/base/services/datasync.py
+++ b/src/pretix/base/services/datasync.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -32,6 +32,7 @@ from django_scopes import scope, scopes_disabled
from pretix.base.datasync.datasync import datasync_providers
from pretix.base.models.datasync import OrderSyncQueue
+from pretix.base.services.tasks import TransactionAwareTask
from pretix.base.signals import periodic_task
from pretix.celery_app import app
@@ -89,7 +90,7 @@ def sync_all():
run_sync(queue)
-@app.task()
+@app.task(base=TransactionAwareTask)
def sync_single(queue_item_id: int):
with scopes_disabled():
queue = (
diff --git a/src/pretix/base/services/export.py b/src/pretix/base/services/export.py
index ee076cd8d..c1fbe0664 100644
--- a/src/pretix/base/services/export.py
+++ b/src/pretix/base/services/export.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -49,7 +49,7 @@ from pretix.base.signals import (
periodic_task, register_data_exporters, register_multievent_data_exporters,
)
from pretix.celery_app import app
-from pretix.helpers import OF_SELF
+from pretix.helpers import OF_SELF, repeatable_reads_transaction
from pretix.helpers.urls import build_absolute_uri
logger = logging.getLogger(__name__)
@@ -80,7 +80,12 @@ def export(self, event: Event, fileid: str, provider: str, form_data: Dict[str,
continue
ex = response(event, event.organizer, set_progress)
if ex.identifier == provider:
- d = ex.render(form_data)
+ if ex.repeatable_read:
+ with repeatable_reads_transaction():
+ d = ex.render(form_data)
+ else:
+ d = ex.render(form_data)
+
if d is None:
raise ExportError(
gettext('Your export did not contain any data.')
@@ -151,7 +156,11 @@ def multiexport(self, organizer: Organizer, user: User, device: int, token: int,
gettext('You do not have sufficient permission to perform this export.')
)
- d = ex.render(form_data)
+ if ex.repeatable_read:
+ with repeatable_reads_transaction():
+ d = ex.render(form_data)
+ else:
+ d = ex.render(form_data)
if d is None:
raise ExportError(
gettext('Your export did not contain any data.')
@@ -209,7 +218,11 @@ def _run_scheduled_export(schedule, context: Union[Event, Organizer], exporter,
try:
if not exporter:
raise ExportError("Export type not found.")
- d = exporter.render(schedule.export_form_data)
+ if exporter.repeatable_read:
+ with repeatable_reads_transaction():
+ d = exporter.render(schedule.export_form_data)
+ else:
+ d = exporter.render(schedule.export_form_data)
if d is None:
raise ExportEmptyError(
gettext('Your export did not contain any data.')
diff --git a/src/pretix/base/services/invoices.py b/src/pretix/base/services/invoices.py
index bbc7438dd..704ea90da 100644
--- a/src/pretix/base/services/invoices.py
+++ b/src/pretix/base/services/invoices.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -61,7 +61,9 @@ from pretix.base.models.tax import EU_CURRENCIES
from pretix.base.services.tasks import (
TransactionAwareProfiledEventTask, TransactionAwareTask,
)
-from pretix.base.signals import invoice_line_text, periodic_task
+from pretix.base.signals import (
+ build_invoice_data, invoice_line_text, periodic_task,
+)
from pretix.celery_app import app
from pretix.helpers.database import OF_SELF, rolledback_transaction
from pretix.helpers.models import modelcopy
@@ -82,6 +84,10 @@ def build_invoice(invoice: Invoice) -> Invoice:
lp = invoice.order.payments.last()
+ min_period_start = None
+ max_period_end = None
+ now_dt = now()
+
with (language(invoice.locale, invoice.event.settings.region)):
invoice.invoice_from = invoice.event.settings.get('invoice_address_from')
invoice.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
@@ -208,7 +214,9 @@ def build_invoice(invoice: Invoice) -> Invoice:
positions = list(
invoice.order.positions.select_related('addon_to', 'item', 'tax_rule', 'subevent', 'variation').annotate(
addon_c=Count('addons')
- ).prefetch_related('answers', 'answers__options', 'answers__question').order_by('positionid', 'id')
+ ).prefetch_related(
+ 'answers', 'answers__options', 'answers__question', 'granted_memberships',
+ ).order_by('positionid', 'id')
)
reverse_charge = False
@@ -267,6 +275,10 @@ def build_invoice(invoice: Invoice) -> Invoice:
location=_location_oneliner(location)
)
+ period_start, period_end = _service_period_for_position(invoice, p, now_dt)
+ min_period_start = min(min_period_start or period_start, period_start)
+ max_period_end = min(max_period_end or period_end, period_end)
+
InvoiceLine.objects.create(
position=i,
invoice=invoice,
@@ -277,8 +289,8 @@ def build_invoice(invoice: Invoice) -> Invoice:
item=p.item,
variation=p.variation,
attendee_name=p.attendee_name if invoice.event.settings.invoice_attendee_name else None,
- event_date_from=p.subevent.date_from if invoice.event.has_subevents else invoice.event.date_from,
- event_date_to=p.subevent.date_to if invoice.event.has_subevents else invoice.event.date_to,
+ period_start=period_start,
+ period_end=period_end,
event_location=location if invoice.event.settings.invoice_event_location else None,
tax_rate=p.tax_rate,
tax_code=p.tax_code,
@@ -301,13 +313,29 @@ def build_invoice(invoice: Invoice) -> Invoice:
fee_title = _(fee.get_fee_type_display())
if fee.description:
fee_title += " - " + fee.description
+
+ if min_period_start and max_period_end:
+ # Consider fees to have the same service period as the products sold
+ period_start = min_period_start
+ period_end = max_period_end
+ else:
+ # Usually can only happen if everything except a cancellation fee is removed
+ if invoice.event.settings.invoice_period in ("auto", "auto_no_event", "event_date") and not invoice.event.has_subevents:
+ # Non-series event, let's be backwards-compatible and tag everything with the event period
+ period_start = invoice.event.date_from
+ period_end = invoice.event.date_to
+ else:
+ # We could try to work from the canceled positions, but it doesn't really make sense. A cancellation
+ # fee is not "delivered" at the event date, it is rather effective right now.
+ period_start = period_end = now()
+
InvoiceLine.objects.create(
position=i + offset,
invoice=invoice,
description=fee_title,
gross_value=fee.value,
- event_date_from=None if invoice.event.has_subevents else invoice.event.date_from,
- event_date_to=None if invoice.event.has_subevents else invoice.event.date_to,
+ period_start=period_start,
+ period_end=period_end,
event_location=(
None if invoice.event.has_subevents
else (str(invoice.event.location)
@@ -336,6 +364,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
invoice.reverse_charge = reverse_charge
invoice.save()
+ build_invoice_data.send(sender=invoice.event, invoice=invoice)
return invoice
@@ -348,9 +377,60 @@ def build_cancellation(invoice: Invoice):
line.gross_value *= -1
line.tax_value *= -1
line.save()
+
+ build_invoice_data.send(sender=invoice.event, invoice=invoice)
return invoice
+def _service_period_for_position(invoice, position, invoice_dt):
+ if invoice.event.settings.invoice_period in ("auto", "auto_no_event"):
+ if position.valid_from and position.valid_until:
+ period_start = position.valid_from
+ period_end = position.valid_until
+ elif position.valid_from:
+ period_start = position.valid_from
+ period_end = position.valid_from # weird, but we have nothing else to base this on
+ elif position.valid_until:
+ period_start = min(invoice.order.datetime, position.valid_until)
+ period_end = position.valid_until
+ elif memberships := list(position.granted_memberships.all()):
+ period_start = min(m.date_start for m in memberships)
+ period_end = max(m.date_end for m in memberships)
+ elif invoice.event.has_subevents:
+ if position.subevent:
+ period_start = position.subevent.date_from
+ period_end = position.subevent.date_to
+ else:
+ # Currently impossible case, but might not be in the future and never makes
+ # sense to use the event date here
+ period_start = invoice_dt
+ period_end = invoice_dt
+ elif invoice.event.settings.invoice_period == "auto_no_event":
+ period_start = invoice_dt
+ period_end = invoice_dt
+ else:
+ period_start = invoice.event.date_from
+ period_end = invoice.event.date_to
+ elif invoice.event.settings.invoice_period == "order_date":
+ period_start = invoice.order.datetime
+ period_end = invoice.order.datetime
+ elif invoice.event.settings.invoice_period == "event_date":
+ if position.subevent:
+ period_start = position.subevent.date_from
+ period_end = position.subevent.date_to
+ else:
+ period_start = invoice.event.date_from
+ period_end = invoice.event.date_to
+ elif invoice.event.settings.invoice_period == "invoice_date":
+ period_start = period_end = invoice_dt
+ else:
+ raise ValueError(f"Invalid invoice period setting '{invoice.event.settings.invoice_period}'")
+
+ if not period_end:
+ period_end = period_start
+ return period_start, period_end
+
+
def generate_cancellation(invoice: Invoice, trigger_pdf=True):
if invoice.canceled:
raise ValueError("Invoice should not be canceled twice.")
@@ -456,6 +536,12 @@ def build_preview_invoice_pdf(event):
if not locale or locale == '__user__':
locale = event.settings.locale
+ if event.settings.invoice_period in ("auto", "auto_no_event", "event_date"):
+ period_start = event.date_from
+ period_end = event.date_to or event.date_from
+ else:
+ period_start = period_end = timezone.now()
+
with rolledback_transaction(), language(locale, event.settings.region):
order = event.orders.create(
status=Order.STATUS_PENDING, datetime=timezone.now(),
@@ -506,8 +592,8 @@ def build_preview_invoice_pdf(event):
invoice=invoice, description=_("Sample product {}").format(i + 1),
gross_value=tax.gross, tax_value=tax.tax,
tax_rate=tax.rate, tax_name=tax.name, tax_code=tax.code,
- event_date_from=event.date_from,
- event_date_to=event.date_to,
+ period_start=period_start,
+ period_end=period_end,
event_location=event.settings.invoice_event_location,
)
else:
@@ -515,8 +601,8 @@ def build_preview_invoice_pdf(event):
InvoiceLine.objects.create(
invoice=invoice, description=_("Sample product A"),
gross_value=100, tax_value=0, tax_rate=0, tax_code=None,
- event_date_from=event.date_from,
- event_date_to=event.date_to,
+ period_start=period_start,
+ period_end=period_end,
event_location=event.settings.invoice_event_location,
)
@@ -587,6 +673,7 @@ def send_invoices_to_organizer(sender, **kwargs):
event=i.event,
invoices=[i],
auto_email=True,
+ plain_text_only=True,
)
i.sent_to_organizer = True
else:
diff --git a/src/pretix/base/services/locking.py b/src/pretix/base/services/locking.py
index 08237c42c..ee666c335 100644
--- a/src/pretix/base/services/locking.py
+++ b/src/pretix/base/services/locking.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/mail.py b/src/pretix/base/services/mail.py
index 3c614941f..03bd489e7 100644
--- a/src/pretix/base/services/mail.py
+++ b/src/pretix/base/services/mail.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -470,9 +470,11 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
logger.exception('Could not attach invoice to email')
pass
- if attach_size < settings.FILE_UPLOAD_MAX_SIZE_EMAIL_ATTACHMENT - 1:
+ if attach_size * 1.37 < settings.FILE_UPLOAD_MAX_SIZE_EMAIL_ATTACHMENT - 1024 * 1024:
# Do not attach more than (limit - 1 MB) in tickets (1MB space for invoice, email itself, …),
# it will bounce way to often.
+ # 1 MB is the buffer for the rest of the email (text, invoice, calendar, pictures)
+ # 1.37 is the factor for base64 encoding https://en.wikipedia.org/wiki/Base64
for a in args:
try:
email.attach(*a)
diff --git a/src/pretix/base/services/media.py b/src/pretix/base/services/media.py
index 787b009fc..c431e79ae 100644
--- a/src/pretix/base/services/media.py
+++ b/src/pretix/base/services/media.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/memberships.py b/src/pretix/base/services/memberships.py
index fc52d76cc..fb2efbe71 100644
--- a/src/pretix/base/services/memberships.py
+++ b/src/pretix/base/services/memberships.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/modelimport.py b/src/pretix/base/services/modelimport.py
index 4c37a6c99..3ef774b70 100644
--- a/src/pretix/base/services/modelimport.py
+++ b/src/pretix/base/services/modelimport.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -19,6 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
+import logging
from decimal import Decimal
from typing import List
@@ -33,8 +34,8 @@ from pretix.base.modelimport import DataImportError, ImportColumn, parse_csv
from pretix.base.modelimport_orders import get_order_import_columns
from pretix.base.modelimport_vouchers import get_voucher_import_columns
from pretix.base.models import (
- CachedFile, Event, InvoiceAddress, Order, OrderPayment, OrderPosition,
- User, Voucher,
+ CachedFile, Event, InvoiceAddress, LogEntry, Order, OrderPayment,
+ OrderPosition, User, Voucher,
)
from pretix.base.models.orders import Transaction
from pretix.base.services.invoices import generate_invoice, invoice_qualified
@@ -43,6 +44,8 @@ from pretix.base.services.tasks import ProfiledEventTask
from pretix.base.signals import order_paid, order_placed
from pretix.celery_app import app
+logger = logging.getLogger(__name__)
+
def _validate(cf: CachedFile, charset: str, cols: List[ImportColumn], settings: dict):
try:
@@ -175,6 +178,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user,
raise DataImportError(_('The seat you selected has already been taken. Please select a different seat.'))
save_transactions = []
+ save_logentries = []
for o in orders:
o.total = sum([c.price for c in o._positions]) # currently no support for fees
if o.total == Decimal('0.00'):
@@ -211,17 +215,19 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user,
o._address.save()
for c in cols:
c.save(o)
- o.log_action(
+ save_logentries.append(o.log_action(
'pretix.event.order.placed',
user=user,
- data={'source': 'import'}
- )
+ data={'source': 'import'},
+ save=False,
+ ))
save_transactions += o.create_transactions(is_new=True, fees=[], positions=o._positions, save=False)
Transaction.objects.bulk_create(save_transactions)
+ LogEntry.bulk_create_and_postprocess(save_logentries)
for o in orders:
with language(o.locale, event.settings.region):
- order_placed.send(event, order=o)
+ order_placed.send(event, order=o, bulk=True)
if o.status == Order.STATUS_PAID:
order_paid.send(event, order=o)
@@ -230,7 +236,13 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user,
(event.settings.get('invoice_generate') == 'paid' and o.status == Order.STATUS_PAID)
) and not o.invoices.last()
if gen_invoice:
- generate_invoice(o, trigger_pdf=True)
+ try:
+ generate_invoice(o, trigger_pdf=True)
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ o.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
except DataImportError:
raise ValidationError(_('We were not able to process your request completely as the server was too busy. '
'Please try again.'))
@@ -286,13 +298,16 @@ def import_vouchers(event: Event, fileid: str, settings: dict, locale: str, user
raise DataImportError(
_('The seat you selected has already been taken. Please select a different seat.'))
+ save_logentries = []
for v in vouchers:
v.save()
- v.log_action(
+ save_logentries.append(v.log_action(
'pretix.voucher.added',
user=user,
- data={'source': 'import'}
- )
+ data={'source': 'import'},
+ save=False,
+ ))
for c in cols:
c.save(v)
+ LogEntry.bulk_create_and_postprocess(save_logentries)
cf.delete()
diff --git a/src/pretix/base/services/notifications.py b/src/pretix/base/services/notifications.py
index 0680482f2..357ad8fc6 100644
--- a/src/pretix/base/services/notifications.py
+++ b/src/pretix/base/services/notifications.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -41,7 +41,11 @@ def notify(logentry_ids: list):
if not isinstance(logentry_ids, list):
logentry_ids = [logentry_ids]
- qs = LogEntry.all.select_related('event', 'event__organizer').filter(id__in=logentry_ids)
+ qs = LogEntry.all.select_related(
+ 'event', 'event__organizer'
+ ).order_by(
+ 'action_type', 'event_id',
+ ).filter(id__in=logentry_ids)
_event, _at, notify_specific, notify_global = None, None, None, None
for logentry in qs:
diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py
index 319084816..bfe817d0f 100644
--- a/src/pretix/base/services/orders.py
+++ b/src/pretix/base/services/orders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -264,7 +264,13 @@ def reactivate_order(order: Order, force: bool=False, user: User=None, auth=None
num_invoices = order.invoices.filter(is_cancellation=False).count()
if num_invoices > 0 and order.invoices.filter(is_cancellation=True).count() >= num_invoices and invoice_qualified(order):
- generate_invoice(order)
+ try:
+ generate_invoice(order)
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
def extend_order(order: Order, new_date: datetime, force: bool=False, valid_if_pending: bool=None, user: User=None, auth=None):
@@ -312,7 +318,13 @@ def extend_order(order: Order, new_date: datetime, force: bool=False, valid_if_p
if was_expired:
num_invoices = order.invoices.filter(is_cancellation=False).count()
if num_invoices > 0 and order.invoices.filter(is_cancellation=True).count() >= num_invoices and invoice_qualified(order):
- generate_invoice(order)
+ try:
+ generate_invoice(order)
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
order.create_transactions()
with transaction.atomic():
@@ -397,13 +409,19 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None, force=False
if order.event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
if not invoice:
- invoice = generate_invoice(
- order,
- # send_mail will trigger PDF generation later
- trigger_pdf=not transmit_invoice_mail
- )
- if transmit_invoice_task:
- transmit_invoice.apply_async(args=(order.event_id, invoice.pk, False))
+ try:
+ invoice = generate_invoice(
+ order,
+ # send_mail will trigger PDF generation later
+ trigger_pdf=not transmit_invoice_mail
+ )
+ if transmit_invoice_task:
+ transmit_invoice.apply_async(args=(order.event_id, invoice.pk, False))
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
if send_mail:
with language(order.locale, order.event.settings.region):
@@ -608,7 +626,13 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
order.save(update_fields=['status', 'cancellation_date', 'total'])
if cancel_invoice and i:
- invoices.append(generate_invoice(order))
+ try:
+ invoices.append(generate_invoice(order))
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
else:
order.status = Order.STATUS_CANCELED
order.cancellation_date = now()
@@ -1091,7 +1115,7 @@ def _create_order(event: Event, *, email: str, positions: List[CartPosition], no
for msg in meta_info.get('confirm_messages', []):
order.log_action('pretix.event.order.consent', data={'msg': msg})
- order_placed.send(event, order=order)
+ order_placed.send(event, order=order, bulk=False)
return order, payments
@@ -1306,13 +1330,19 @@ def _perform_order(event: Event, payment_requests: List[dict], position_ids: Lis
)
)
if invoice_required:
- invoice = generate_invoice(
- order,
- # send_mail will trigger PDF generation later
- trigger_pdf=not transmit_invoice_mail
- )
- if transmit_invoice_task:
- transmit_invoice.apply_async(args=(event.pk, invoice.pk, False))
+ try:
+ invoice = generate_invoice(
+ order,
+ # send_mail will trigger PDF generation later
+ trigger_pdf=not transmit_invoice_mail
+ )
+ if transmit_invoice_task:
+ transmit_invoice.apply_async(args=(event.pk, invoice.pk, False))
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
if order.email:
if order.require_approval:
@@ -2701,7 +2731,13 @@ class OrderChangeManager:
)
if split_order.total != Decimal('0.00') and self.order.invoices.filter(is_cancellation=False).last():
- generate_invoice(split_order)
+ try:
+ generate_invoice(split_order)
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ split_order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
order_split.send(sender=self.order.event, original=self.order, split_order=split_order)
return split_order
@@ -2812,20 +2848,32 @@ class OrderChangeManager:
if order_now_qualified:
if invoice_should_be_generated_now:
- if i and not i.canceled:
- self._invoices.append(generate_cancellation(i))
- self._invoices.append(generate_invoice(self.order))
+ try:
+ if i and not i.canceled:
+ self._invoices.append(generate_cancellation(i))
+ self._invoices.append(generate_invoice(self.order))
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ self.order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
elif invoice_should_be_generated_later:
self.order.invoice_dirty = True
self.order.save(update_fields=["invoice_dirty"])
else:
- if i and not i.canceled:
- self._invoices.append(generate_cancellation(i))
+ try:
+ if i and not i.canceled:
+ self._invoices.append(generate_cancellation(i))
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ self.order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
def _check_complete_cancel(self):
current = self.order.positions.count()
cancels = sum([
- 1 + o.position.addons.count() for o in self._operations if isinstance(o, self.CancelOperation)
+ 1 + o.position.addons.filter(canceled=False).count() for o in self._operations if isinstance(o, self.CancelOperation)
]) + len([
o for o in self._operations if isinstance(o, self.SplitOperation)
])
@@ -3039,6 +3087,7 @@ def _try_auto_refund(order, auto_refund=True, manual_refund=False, allow_partial
expires=order.event.organizer.default_gift_card_expiry if giftcard_expires is _unset else giftcard_expires,
conditions=giftcard_conditions,
currency=order.event.currency,
+ customer=order.customer,
testmode=order.testmode
)
giftcard.log_action('pretix.giftcards.created', data={})
@@ -3246,8 +3295,14 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay
has_active_invoice = i and not i.canceled
if has_active_invoice and order.total != oldtotal:
- generate_cancellation(i)
- generate_invoice(order)
+ try:
+ generate_cancellation(i)
+ generate_invoice(order)
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
new_invoice_created = True
elif (not has_active_invoice or order.invoice_dirty) and invoice_qualified(order):
@@ -3255,13 +3310,19 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay
order.event.settings.get('invoice_generate') == 'paid' and
new_payment.payment_provider.requires_invoice_immediately
):
- if has_active_invoice:
- generate_cancellation(i)
- i = generate_invoice(order)
- new_invoice_created = True
- order.log_action('pretix.event.order.invoice.generated', data={
- 'invoice': i.pk
- })
+ try:
+ if has_active_invoice:
+ generate_cancellation(i)
+ i = generate_invoice(order)
+ new_invoice_created = True
+ order.log_action('pretix.event.order.invoice.generated', data={
+ 'invoice': i.pk
+ })
+ except Exception as e:
+ logger.exception("Could not generate invoice.")
+ order.log_action("pretix.event.order.invoice.failed", data={
+ "exception": str(e)
+ })
order.create_transactions()
return old_fee, new_fee, fee, new_payment, new_invoice_created
diff --git a/src/pretix/base/services/placeholders.py b/src/pretix/base/services/placeholders.py
index 53fc2918f..c4cdc03c3 100644
--- a/src/pretix/base/services/placeholders.py
+++ b/src/pretix/base/services/placeholders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/pricing.py b/src/pretix/base/services/pricing.py
index ac6b1a13e..5ac9dbea4 100644
--- a/src/pretix/base/services/pricing.py
+++ b/src/pretix/base/services/pricing.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/quotas.py b/src/pretix/base/services/quotas.py
index 4511309e7..124e90e39 100644
--- a/src/pretix/base/services/quotas.py
+++ b/src/pretix/base/services/quotas.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -26,7 +26,7 @@ from itertools import zip_longest
import django_redis
from django.conf import settings
-from django.db import models
+from django.db import connection, models
from django.db.models import (
Case, Count, F, Func, Max, OuterRef, Q, Subquery, Sum, Value, When,
prefetch_related_objects,
@@ -64,7 +64,8 @@ class QuotaAvailability:
* count_cart (dict mapping quotas to ints)
"""
- def __init__(self, count_waitinglist=True, ignore_closed=False, full_results=False, early_out=True):
+ def __init__(self, count_waitinglist=True, ignore_closed=False, full_results=False, early_out=True,
+ allow_repeatable_read=False):
"""
Initialize a new quota availability calculator
@@ -86,6 +87,8 @@ class QuotaAvailability:
keep the database-level quota cache up to date so backend overviews render quickly. If you
do not care about keeping the cache up to date, you can set this to ``False`` for further
performance improvements.
+
+ :param allow_repeatable_read: Allow to run this even in REPEATABLE READ mode, generally not advised.
"""
self._queue = []
self._count_waitinglist = count_waitinglist
@@ -95,6 +98,7 @@ class QuotaAvailability:
self._var_to_quotas = defaultdict(set)
self._early_out = early_out
self._quota_objects = {}
+ self._allow_repeatable_read = allow_repeatable_read
self.results = {}
self.count_paid_orders = defaultdict(int)
self.count_pending_orders = defaultdict(int)
@@ -119,6 +123,10 @@ class QuotaAvailability:
Compute the queued quotas. If ``allow_cache`` is set, results may also be taken from a cache that might
be a few minutes outdated. In this case, you may not rely on the results in the ``count_*`` properties.
"""
+ if not self._allow_repeatable_read and getattr(connection, "tx_in_repeatable_read", False):
+ raise ValueError("You cannot compute quotas in REPEATABLE READ mode unless you explicitly opted in to "
+ "do so.")
+
now_dt = now_dt or now()
quota_ids_set = {q.id for q in self._queue}
if not quota_ids_set:
diff --git a/src/pretix/base/services/seating.py b/src/pretix/base/services/seating.py
index 8408f3ee2..5a76f9fca 100644
--- a/src/pretix/base/services/seating.py
+++ b/src/pretix/base/services/seating.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/shredder.py b/src/pretix/base/services/shredder.py
index 0411e6fa8..84ef4eee0 100644
--- a/src/pretix/base/services/shredder.py
+++ b/src/pretix/base/services/shredder.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/stats.py b/src/pretix/base/services/stats.py
index 79e86afe0..eef5ac465 100644
--- a/src/pretix/base/services/stats.py
+++ b/src/pretix/base/services/stats.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/tasks.py b/src/pretix/base/services/tasks.py
index 56673c4fa..fa315b463 100644
--- a/src/pretix/base/services/tasks.py
+++ b/src/pretix/base/services/tasks.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/tax.py b/src/pretix/base/services/tax.py
index e4eb37a10..781374c56 100644
--- a/src/pretix/base/services/tax.py
+++ b/src/pretix/base/services/tax.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/tickets.py b/src/pretix/base/services/tickets.py
index b0244253e..fc50e7968 100644
--- a/src/pretix/base/services/tickets.py
+++ b/src/pretix/base/services/tickets.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/update_check.py b/src/pretix/base/services/update_check.py
index 1f7b93b4d..5a23b3388 100644
--- a/src/pretix/base/services/update_check.py
+++ b/src/pretix/base/services/update_check.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/vouchers.py b/src/pretix/base/services/vouchers.py
index d0cbb9d68..452dfbaa8 100644
--- a/src/pretix/base/services/vouchers.py
+++ b/src/pretix/base/services/vouchers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/services/waitinglist.py b/src/pretix/base/services/waitinglist.py
index 59e912a9f..238212ea0 100644
--- a/src/pretix/base/services/waitinglist.py
+++ b/src/pretix/base/services/waitinglist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py
index fbc52b31a..3bf4ead9e 100644
--- a/src/pretix/base/settings.py
+++ b/src/pretix/base/settings.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -1098,6 +1098,35 @@ DEFAULTS = {
help_text=_("Invoices will never be automatically generated for free orders.")
)
},
+ 'invoice_period': {
+ 'default': 'auto',
+ 'type': str,
+ 'form_class': forms.ChoiceField,
+ 'serializer_class': serializers.ChoiceField,
+ 'serializer_kwargs': dict(
+ choices=(
+ ('auto', _('Automatic based on ticket-specific validity, membership validity, event series date, or event date')),
+ ('auto_no_event', _('Automatic, but prefer invoice date over event date')),
+ ('event_date', _('Event date')),
+ ('order_date', _('Order date')),
+ ('invoice_date', _('Invoice date')),
+ ),
+ ),
+ 'form_kwargs': dict(
+ label=_("Date of service"),
+ widget=forms.RadioSelect,
+ choices=(
+ ('auto', _('Automatic based on ticket-specific validity, membership validity, event series date, or event date')),
+ ('auto_no_event', _('Automatic, but prefer invoice date over event date')),
+ ('event_date', _('Event date')),
+ ('order_date', _('Order date')),
+ ('invoice_date', _('Invoice date')),
+ ),
+ help_text=_("This controls what dates are shown on the invoice, but is especially important for "
+ "electronic invoicing."),
+ required=True,
+ )
+ },
'invoice_reissue_after_modify': {
'default': 'False',
'type': bool,
diff --git a/src/pretix/base/shredder.py b/src/pretix/base/shredder.py
index b1d22a014..a8110e987 100644
--- a/src/pretix/base/shredder.py
+++ b/src/pretix/base/shredder.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/signals.py b/src/pretix/base/signals.py
index 8e1842200..3ab54bf0e 100644
--- a/src/pretix/base/signals.py
+++ b/src/pretix/base/signals.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -170,7 +170,7 @@ class PluginSignal(Generic[T], django.dispatch.Signal):
second receiver and so on. The return value of the last receiver is returned by this method.
"""
if sender and not isinstance(sender, self.type):
- raise ValueError("Sender needs to be an event.")
+ raise ValueError(f"Sender needs to be of type {self.type}.")
response = named.get(chain_kwarg_name)
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
@@ -192,7 +192,7 @@ class PluginSignal(Generic[T], django.dispatch.Signal):
stopping the response chain at the offending receiver.
"""
if sender and not isinstance(sender, self.type):
- raise ValueError("Sender needs to be an event.")
+ raise ValueError(f"Sender needs to be of type {self.type}.")
responses = []
if (
@@ -596,6 +596,18 @@ multiple events. Receivers should return a subclass of pretix.base.exporter.Base
The ``sender`` keyword argument will contain an organizer.
"""
+build_invoice_data = EventPluginSignal()
+"""
+Arguments: ``invoice``
+
+This signal is sent out every time an invoice is built, after the invoice model was created
+and filled and before the PDF generation task is started. You can use this to make changes
+to the invoice, but we recommend to mostly use it to add content to ``Invoice.plugin_data``.
+You are responsible for saving any changes to the database.
+
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
+"""
+
validate_order = EventPluginSignal()
"""
Arguments: ``payments``, ``positions``, ``email``, ``locale``, ``invoice_address``,
@@ -653,12 +665,13 @@ As with all event-plugin signals, the ``sender`` keyword argument will contain t
order_placed = EventPluginSignal()
"""
-Arguments: ``order``
+Arguments: ``order``, ``bulk``
This signal is sent out every time an order is placed. The order object is given
-as the first argument. This signal is *not* sent out if an order is created through
-splitting an existing order, so you can not expect to see all orders by listening
-to this signal.
+as the first argument. The ``bulk`` argument specifies whether the order was placed
+as part of a bulk action, e.g. an import from a file.
+This signal is *not* sent out if an order is created through splitting an existing order,
+so you can not expect to see all orders by listening to this signal.
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
diff --git a/src/pretix/base/templates/error.html b/src/pretix/base/templates/error.html
index ad1e120a7..790f80d15 100644
--- a/src/pretix/base/templates/error.html
+++ b/src/pretix/base/templates/error.html
@@ -11,6 +11,7 @@
+ {% block custom_header %}{% endblock %}
diff --git a/src/pretix/base/templates/pretixbase/email/base.html b/src/pretix/base/templates/pretixbase/email/base.html
index 43a14a5d9..e8375118d 100644
--- a/src/pretix/base/templates/pretixbase/email/base.html
+++ b/src/pretix/base/templates/pretixbase/email/base.html
@@ -174,6 +174,12 @@
.order-details > thead > tr > td:first-child {
width: 20%;
}
+ .order-details, .cart-table {
+ border-spacing: 0;
+ }
+ .order-details td:first-child, .cart-table td:first-child {
+ padding-left: 0;
+ }
.order-details td {
font-size: 12px;
}
diff --git a/src/pretix/base/templates/pretixbase/email/cancel_confirm.txt b/src/pretix/base/templates/pretixbase/email/cancel_confirm.txt
new file mode 100644
index 000000000..5e3043156
--- /dev/null
+++ b/src/pretix/base/templates/pretixbase/email/cancel_confirm.txt
@@ -0,0 +1,10 @@
+{% load i18n %}
+{% trans "You have requested us to cancel an event which includes a larger bulk-refund:" %}
+
+{% trans "Event" %}: {{ event }}
+
+{% trans "Estimated refund amount" %}: **{{ amount }}**
+
+{% trans "Please confirm that you want to proceed by coping the following confirmation code into the cancellation form:" %}
+
+**{{ confirmation_code }}**
diff --git a/src/pretix/base/templates/pretixbase/email/order_details.html b/src/pretix/base/templates/pretixbase/email/order_details.html
index 4824cd9fe..e3c0a0a82 100644
--- a/src/pretix/base/templates/pretixbase/email/order_details.html
+++ b/src/pretix/base/templates/pretixbase/email/order_details.html
@@ -51,42 +51,46 @@
{% else %}
- {% trans "You are receiving this email because you placed an order for the following event:" %}
+ {% blocktrans trimmed with event=event.name %}
+ You are receiving this email because you placed an order for {{ event }}.
+ {% endblocktrans %}
+ {% endif %}
+ {% if not event.has_subevents and event.location %}
+
+
+ {% trans "Location" %}:
+
+
+ {{ event.location|oneline }}
+
+
+ {% endif %}
{% if cart %}
- {% trans "Details:" %}
+ {% trans "Details" %}:
@@ -129,7 +133,7 @@
{% endif %}
- {% trans "Contact:" %}
+ {% trans "Contact" %}:
{{ event.organizer }}
diff --git a/src/pretix/base/templates/pretixbase/email/simple_logo.html b/src/pretix/base/templates/pretixbase/email/simple_logo.html
index df8902c77..676cae5cd 100644
--- a/src/pretix/base/templates/pretixbase/email/simple_logo.html
+++ b/src/pretix/base/templates/pretixbase/email/simple_logo.html
@@ -197,6 +197,12 @@
.order-details > thead > tr > td:first-child {
width: 20%;
}
+ .order-details, .cart-table {
+ border-spacing: 0;
+ }
+ .order-details td:first-child, .cart-table td:first-child {
+ padding-left: 0;
+ }
.order-details td {
font-size: 12px;
}
diff --git a/src/pretix/base/templatetags/__init__.py b/src/pretix/base/templatetags/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/templatetags/__init__.py
+++ b/src/pretix/base/templatetags/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/cache_large.py b/src/pretix/base/templatetags/cache_large.py
index b3e9b7dd4..4bdce26df 100644
--- a/src/pretix/base/templatetags/cache_large.py
+++ b/src/pretix/base/templatetags/cache_large.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/calendarhead.py b/src/pretix/base/templatetags/calendarhead.py
index 912e2a600..f30b274f1 100644
--- a/src/pretix/base/templatetags/calendarhead.py
+++ b/src/pretix/base/templatetags/calendarhead.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/classname.py b/src/pretix/base/templatetags/classname.py
index 1bc239e9b..66cd1dfb9 100644
--- a/src/pretix/base/templatetags/classname.py
+++ b/src/pretix/base/templatetags/classname.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/daterange.py b/src/pretix/base/templatetags/daterange.py
index e51bd517d..a7e6a19bf 100644
--- a/src/pretix/base/templatetags/daterange.py
+++ b/src/pretix/base/templatetags/daterange.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/dialog.py b/src/pretix/base/templatetags/dialog.py
index 0cc422455..b67725f82 100644
--- a/src/pretix/base/templatetags/dialog.py
+++ b/src/pretix/base/templatetags/dialog.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/escapejson.py b/src/pretix/base/templatetags/escapejson.py
index 89b25bf11..abada8654 100644
--- a/src/pretix/base/templatetags/escapejson.py
+++ b/src/pretix/base/templatetags/escapejson.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/eventsignal.py b/src/pretix/base/templatetags/eventsignal.py
index 4a4fb1e62..54f2da5df 100644
--- a/src/pretix/base/templatetags/eventsignal.py
+++ b/src/pretix/base/templatetags/eventsignal.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/icon.py b/src/pretix/base/templatetags/icon.py
index d71319b01..dc10406cd 100644
--- a/src/pretix/base/templatetags/icon.py
+++ b/src/pretix/base/templatetags/icon.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/lists.py b/src/pretix/base/templatetags/lists.py
index 69113e66a..abfb8aa2e 100644
--- a/src/pretix/base/templatetags/lists.py
+++ b/src/pretix/base/templatetags/lists.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/money.py b/src/pretix/base/templatetags/money.py
index ad4eff1cc..edda9904e 100644
--- a/src/pretix/base/templatetags/money.py
+++ b/src/pretix/base/templatetags/money.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/oneline.py b/src/pretix/base/templatetags/oneline.py
index bbfc848a9..f58e4aa93 100644
--- a/src/pretix/base/templatetags/oneline.py
+++ b/src/pretix/base/templatetags/oneline.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/phone_format.py b/src/pretix/base/templatetags/phone_format.py
index c38ff7561..bc30b610c 100644
--- a/src/pretix/base/templatetags/phone_format.py
+++ b/src/pretix/base/templatetags/phone_format.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/rich_text.py b/src/pretix/base/templatetags/rich_text.py
index d77d9ce9c..f38cdeab8 100644
--- a/src/pretix/base/templatetags/rich_text.py
+++ b/src/pretix/base/templatetags/rich_text.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -54,6 +54,19 @@ from tlds import tld_set
register = template.Library()
+
+def build_fediverse_re(tlds):
+ return re.compile(
+ r"""\(* # Match any opening parentheses.
+ @[^@]+@
+ ([\w-]+\.)+(?:{0})(?:\:[0-9]+)?(?!\.\w)\b # xx.yy.tld(:##)?
+ """.format(
+ "|".join(sorted(tlds))
+ ),
+ re.IGNORECASE | re.VERBOSE | re.UNICODE,
+ )
+
+
ALLOWED_TAGS_SNIPPET = {
'a',
'abbr',
@@ -112,6 +125,8 @@ URL_RE = SimpleLazyObject(lambda: build_url_re(tlds=sorted(tld_set, key=len, rev
EMAIL_RE = SimpleLazyObject(lambda: build_email_re(tlds=sorted(tld_set, key=len, reverse=True)))
+FEDIVERSE_RE = SimpleLazyObject(lambda: build_fediverse_re(tlds=sorted(tld_set, key=len, reverse=True)))
+
DOT_ESCAPE = "|escaped-dot-sGnY9LMK|"
@@ -144,9 +159,11 @@ def truelink_callback(attrs, new=False):
https://maps.google.com
"""
- text = re.sub(r'[^a-zA-Z0-9.\-/_ ]', '', attrs.get('_text')) # clean up link text
+ text = re.sub(r'[^a-zA-Z0-9.\-/_@: ]', '', attrs.get('_text')) # clean up link text
url = attrs.get((None, 'href'), '/')
href_url = urllib.parse.urlparse(url)
+
+ # Verify server name of URL names
if (None, 'href') in attrs and URL_RE.match(text) and href_url.scheme not in ('tel', 'mailto'):
# link text looks like a url
if text.startswith('//'):
@@ -154,10 +171,20 @@ def truelink_callback(attrs, new=False):
elif not text.startswith('http'):
text = 'https://' + text
+ text_url = urllib.parse.urlparse(text)
+ if text_url.netloc.split("@")[-1] != href_url.netloc.split("@")[-1] or not href_url.path.startswith(text_url.path):
+ # link text contains an URL that has a different base than the actual URL
+ attrs['_text'] = attrs[None, 'href']
+
+ # Verify server name of mastodon display names (@name@server.tld)
+ if (None, 'href') in attrs and FEDIVERSE_RE.match(text):
+ parts = text.split('@')
+ text = f'https://{parts[2]}/@{parts[1]}'
text_url = urllib.parse.urlparse(text)
if text_url.netloc != href_url.netloc or not href_url.path.startswith(href_url.path):
# link text contains an URL that has a different base than the actual URL
attrs['_text'] = attrs[None, 'href']
+
return attrs
diff --git a/src/pretix/base/templatetags/safelink.py b/src/pretix/base/templatetags/safelink.py
index 3d2d322bd..f60324627 100644
--- a/src/pretix/base/templatetags/safelink.py
+++ b/src/pretix/base/templatetags/safelink.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/textbubble.py b/src/pretix/base/templatetags/textbubble.py
index a0c3a3d30..1d138a76d 100644
--- a/src/pretix/base/templatetags/textbubble.py
+++ b/src/pretix/base/templatetags/textbubble.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/unidecode.py b/src/pretix/base/templatetags/unidecode.py
index 54dbc8325..181fade39 100644
--- a/src/pretix/base/templatetags/unidecode.py
+++ b/src/pretix/base/templatetags/unidecode.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/templatetags/urlreplace.py b/src/pretix/base/templatetags/urlreplace.py
index b4aa92791..a6b4ec307 100644
--- a/src/pretix/base/templatetags/urlreplace.py
+++ b/src/pretix/base/templatetags/urlreplace.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/ticketoutput.py b/src/pretix/base/ticketoutput.py
index cd86ab948..63087a93a 100644
--- a/src/pretix/base/ticketoutput.py
+++ b/src/pretix/base/ticketoutput.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/timeframes.py b/src/pretix/base/timeframes.py
index 10dca6965..f3f2b3a4d 100644
--- a/src/pretix/base/timeframes.py
+++ b/src/pretix/base/timeframes.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/timeline.py b/src/pretix/base/timeline.py
index b44076627..be9d1d6b9 100644
--- a/src/pretix/base/timeline.py
+++ b/src/pretix/base/timeline.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/timemachine.py b/src/pretix/base/timemachine.py
index 9bb647321..c8ba4c2c2 100644
--- a/src/pretix/base/timemachine.py
+++ b/src/pretix/base/timemachine.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/validators.py b/src/pretix/base/validators.py
index 3b2a63531..15cf67b0f 100644
--- a/src/pretix/base/validators.py
+++ b/src/pretix/base/validators.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/__init__.py b/src/pretix/base/views/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/base/views/__init__.py
+++ b/src/pretix/base/views/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/applepay.py b/src/pretix/base/views/applepay.py
index 768a53d44..a008804b0 100644
--- a/src/pretix/base/views/applepay.py
+++ b/src/pretix/base/views/applepay.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/cachedfiles.py b/src/pretix/base/views/cachedfiles.py
index e425e4805..744ea8c1d 100644
--- a/src/pretix/base/views/cachedfiles.py
+++ b/src/pretix/base/views/cachedfiles.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/csp.py b/src/pretix/base/views/csp.py
index b51a8d3ed..55bce1fed 100644
--- a/src/pretix/base/views/csp.py
+++ b/src/pretix/base/views/csp.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/errors.py b/src/pretix/base/views/errors.py
index c558676c6..7b76973b9 100644
--- a/src/pretix/base/views/errors.py
+++ b/src/pretix/base/views/errors.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/health.py b/src/pretix/base/views/health.py
index c0ea3f38c..874b98770 100644
--- a/src/pretix/base/views/health.py
+++ b/src/pretix/base/views/health.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/js_catalog.py b/src/pretix/base/views/js_catalog.py
index f74f3b69c..0e874fd75 100644
--- a/src/pretix/base/views/js_catalog.py
+++ b/src/pretix/base/views/js_catalog.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/js_helpers.py b/src/pretix/base/views/js_helpers.py
index 693dc0b71..7da2c8395 100644
--- a/src/pretix/base/views/js_helpers.py
+++ b/src/pretix/base/views/js_helpers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/metrics.py b/src/pretix/base/views/metrics.py
index 8df859146..60fe93e2b 100644
--- a/src/pretix/base/views/metrics.py
+++ b/src/pretix/base/views/metrics.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/mixins.py b/src/pretix/base/views/mixins.py
index 41c986a44..f85228d8a 100644
--- a/src/pretix/base/views/mixins.py
+++ b/src/pretix/base/views/mixins.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/redirect.py b/src/pretix/base/views/redirect.py
index c5b65cd1e..687338f4a 100644
--- a/src/pretix/base/views/redirect.py
+++ b/src/pretix/base/views/redirect.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/source.py b/src/pretix/base/views/source.py
index 6316db731..6b09ce9ff 100644
--- a/src/pretix/base/views/source.py
+++ b/src/pretix/base/views/source.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/tasks.py b/src/pretix/base/views/tasks.py
index 949cef639..e763d7fba 100644
--- a/src/pretix/base/views/tasks.py
+++ b/src/pretix/base/views/tasks.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/base/views/webmanifest.py b/src/pretix/base/views/webmanifest.py
index 22a31699a..c85bebc69 100644
--- a/src/pretix/base/views/webmanifest.py
+++ b/src/pretix/base/views/webmanifest.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/celery_app.py b/src/pretix/celery_app.py
index 060c10e5c..f140aefc7 100644
--- a/src/pretix/celery_app.py
+++ b/src/pretix/celery_app.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/__init__.py b/src/pretix/control/__init__.py
index 9fd5bdc50..9616a7bf6 100644
--- a/src/pretix/control/__init__.py
+++ b/src/pretix/control/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/apps.py b/src/pretix/control/apps.py
index 05c626b6a..2e8e4d87e 100644
--- a/src/pretix/control/apps.py
+++ b/src/pretix/control/apps.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/context.py b/src/pretix/control/context.py
index cde58295a..4480a1148 100644
--- a/src/pretix/control/context.py
+++ b/src/pretix/control/context.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/__init__.py b/src/pretix/control/forms/__init__.py
index 42a0fdf6d..d72a0ca34 100644
--- a/src/pretix/control/forms/__init__.py
+++ b/src/pretix/control/forms/__init__.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/checkin.py b/src/pretix/control/forms/checkin.py
index 32d4021e3..c1dee0443 100644
--- a/src/pretix/control/forms/checkin.py
+++ b/src/pretix/control/forms/checkin.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/discounts.py b/src/pretix/control/forms/discounts.py
index 44ad2386c..e73babde3 100644
--- a/src/pretix/control/forms/discounts.py
+++ b/src/pretix/control/forms/discounts.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py
index 1b4f6cdc9..2c67d74b6 100644
--- a/src/pretix/control/forms/event.py
+++ b/src/pretix/control/forms/event.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -857,6 +857,7 @@ class InvoiceSettingsForm(EventSettingsValidationMixin, SettingsForm):
'invoice_show_payments',
'invoice_reissue_after_modify',
'invoice_generate',
+ 'invoice_period',
'invoice_attendee_name',
'invoice_event_location',
'invoice_include_expire_date',
diff --git a/src/pretix/control/forms/exports.py b/src/pretix/control/forms/exports.py
index a1864280e..7e751df46 100644
--- a/src/pretix/control/forms/exports.py
+++ b/src/pretix/control/forms/exports.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/filter.py b/src/pretix/control/forms/filter.py
index d41d4afc8..6e330bb8f 100644
--- a/src/pretix/control/forms/filter.py
+++ b/src/pretix/control/forms/filter.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/global_settings.py b/src/pretix/control/forms/global_settings.py
index 41f4b5745..518579968 100644
--- a/src/pretix/control/forms/global_settings.py
+++ b/src/pretix/control/forms/global_settings.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py
index 06aa2496b..5d0e5140a 100644
--- a/src/pretix/control/forms/item.py
+++ b/src/pretix/control/forms/item.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/mailsetup.py b/src/pretix/control/forms/mailsetup.py
index bece8832f..95c9dddb5 100644
--- a/src/pretix/control/forms/mailsetup.py
+++ b/src/pretix/control/forms/mailsetup.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/mapping.py b/src/pretix/control/forms/mapping.py
index 1da418688..cb9aa7284 100644
--- a/src/pretix/control/forms/mapping.py
+++ b/src/pretix/control/forms/mapping.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/modelimport.py b/src/pretix/control/forms/modelimport.py
index c96cf29c4..9e6c4869f 100644
--- a/src/pretix/control/forms/modelimport.py
+++ b/src/pretix/control/forms/modelimport.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -21,6 +21,8 @@
#
from django import forms
from django.core.exceptions import ValidationError
+from django.utils.functional import lazy
+from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from pretix.base.modelimport_orders import get_order_import_columns
@@ -71,6 +73,9 @@ class ProcessForm(forms.Form):
raise NotImplementedError() # noqa
+format_html_lazy = lazy(format_html, str)
+
+
class OrdersProcessForm(ProcessForm):
orders = forms.ChoiceField(
label=_('Import mode'),
@@ -91,7 +96,11 @@ class OrdersProcessForm(ProcessForm):
)
testmode = forms.BooleanField(
label=_('Create orders as test mode orders'),
- required=False
+ required=False,
+ help_text=format_html_lazy(
+ '
{}
',
+ _('Orders not created in test mode cannot be deleted again after import.')
+ )
)
def __init__(self, *args, **kwargs):
@@ -100,6 +109,8 @@ class OrdersProcessForm(ProcessForm):
initital['testmode'] = self.event.testmode
kwargs['initial'] = initital
super().__init__(*args, **kwargs)
+ if not self.event.testmode:
+ self.fields["testmode"].help_text = ""
def get_columns(self):
return get_order_import_columns(self.event)
diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py
index 881920fca..9d2dc82d6 100644
--- a/src/pretix/control/forms/orders.py
+++ b/src/pretix/control/forms/orders.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -1030,3 +1030,27 @@ class EventCancelForm(FormPlaceholderMixin, forms.Form):
if self.event.has_subevents and not d['subevent'] and not d['all_subevents'] and not d.get('subevents_from'):
raise ValidationError(_('Please confirm that you want to cancel ALL dates in this event series.'))
return d
+
+
+class EventCancelConfirmForm(forms.Form):
+ confirm = forms.BooleanField(
+ label=_("I understand that this is not reversible and want to continue"),
+ required=True,
+ )
+ confirmation_code = forms.CharField(
+ label=_("Confirmation code"),
+ help_text=_("We have just emailed you a confirmation code to enter to confirm this action"),
+ required=True,
+ )
+
+ def __init__(self, *args, **kwargs):
+ self.code = kwargs.pop("confirmation_code")
+ super().__init__(*args, **kwargs)
+ if not self.code:
+ del self.fields["confirmation_code"]
+
+ def clean_confirmation_code(self):
+ val = self.cleaned_data['confirmation_code']
+ if val != self.code:
+ raise ValidationError(_('The confirmation code is incorrect.'))
+ return val
diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py
index e3226c776..c8f63914f 100644
--- a/src/pretix/control/forms/organizer.py
+++ b/src/pretix/control/forms/organizer.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -731,6 +731,21 @@ class GiftCardCreateForm(forms.ModelForm):
kwargs['initial'] = initial
super().__init__(*args, **kwargs)
+ if self.organizer.settings.customer_accounts:
+ self.fields['customer'].queryset = self.organizer.customers.all()
+ self.fields['customer'].widget = Select2(
+ attrs={
+ 'data-model-select2': 'generic',
+ 'data-select2-url': reverse('control:organizer.customers.select2', kwargs={
+ 'organizer': self.organizer.slug,
+ }),
+ }
+ )
+ self.fields['customer'].widget.choices = self.fields['customer'].choices
+ self.fields['customer'].required = False
+ else:
+ del self.fields['customer']
+
def clean_secret(self):
s = self.cleaned_data['secret']
if GiftCard.objects.filter(
@@ -749,9 +764,10 @@ class GiftCardCreateForm(forms.ModelForm):
class Meta:
model = GiftCard
- fields = ['secret', 'currency', 'testmode', 'expires', 'conditions']
+ fields = ['secret', 'currency', 'testmode', 'expires', 'conditions', 'customer']
field_classes = {
- 'expires': SplitDateTimeField
+ 'expires': SplitDateTimeField,
+ 'customer': SafeModelChoiceField,
}
widgets = {
'expires': SplitDateTimePickerWidget,
@@ -762,10 +778,11 @@ class GiftCardCreateForm(forms.ModelForm):
class GiftCardUpdateForm(forms.ModelForm):
class Meta:
model = GiftCard
- fields = ['expires', 'conditions', 'owner_ticket']
+ fields = ['expires', 'conditions', 'owner_ticket', 'customer']
field_classes = {
'expires': SplitDateTimeField,
'owner_ticket': SafeOrderPositionChoiceField,
+ 'customer': SafeModelChoiceField,
}
widgets = {
'expires': SplitDateTimePickerWidget,
@@ -788,6 +805,21 @@ class GiftCardUpdateForm(forms.ModelForm):
self.fields['owner_ticket'].widget.choices = self.fields['owner_ticket'].choices
self.fields['owner_ticket'].required = False
+ if organizer.settings.customer_accounts:
+ self.fields['customer'].queryset = organizer.customers.all()
+ self.fields['customer'].widget = Select2(
+ attrs={
+ 'data-model-select2': 'generic',
+ 'data-select2-url': reverse('control:organizer.customers.select2', kwargs={
+ 'organizer': organizer.slug,
+ }),
+ }
+ )
+ self.fields['customer'].widget.choices = self.fields['customer'].choices
+ self.fields['customer'].required = False
+ else:
+ del self.fields['customer']
+
class ReusableMediumUpdateForm(forms.ModelForm):
error_messages = {
diff --git a/src/pretix/control/forms/renderers.py b/src/pretix/control/forms/renderers.py
index 786a060d4..8cc21abc0 100644
--- a/src/pretix/control/forms/renderers.py
+++ b/src/pretix/control/forms/renderers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/rrule.py b/src/pretix/control/forms/rrule.py
index bfa7810e0..e144ed131 100644
--- a/src/pretix/control/forms/rrule.py
+++ b/src/pretix/control/forms/rrule.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/subevents.py b/src/pretix/control/forms/subevents.py
index c0fcc6f29..b0a78fd7f 100644
--- a/src/pretix/control/forms/subevents.py
+++ b/src/pretix/control/forms/subevents.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -390,7 +390,8 @@ class QuotaFormSet(I18nInlineFormSet):
use_required_attribute=False,
locales=self.locales,
event=self.event,
- items=self.items
+ items=self.items,
+ searchable_selection=self.searchable_selection,
)
self.add_fields(form, None)
return form
diff --git a/src/pretix/control/forms/users.py b/src/pretix/control/forms/users.py
index 08cf6dcef..7f813a13d 100644
--- a/src/pretix/control/forms/users.py
+++ b/src/pretix/control/forms/users.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/vouchers.py b/src/pretix/control/forms/vouchers.py
index 53bf3dccf..5138b7b7c 100644
--- a/src/pretix/control/forms/vouchers.py
+++ b/src/pretix/control/forms/vouchers.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/waitinglist.py b/src/pretix/control/forms/waitinglist.py
index 3a1b7f3bf..7dc33c4a9 100644
--- a/src/pretix/control/forms/waitinglist.py
+++ b/src/pretix/control/forms/waitinglist.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/forms/widgets.py b/src/pretix/control/forms/widgets.py
index b65cc22bc..d054be63a 100644
--- a/src/pretix/control/forms/widgets.py
+++ b/src/pretix/control/forms/widgets.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py
index 29de5a52c..552d07518 100644
--- a/src/pretix/control/logdisplay.py
+++ b/src/pretix/control/logdisplay.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
@@ -455,7 +455,7 @@ class OrderDataSyncSuccessLogEntryType(OrderDataSyncLogEntryType):
links.append(", ".join(
prov.get_external_link_html(logentry.event, obj['external_link_href'], obj['external_link_display_name'])
for obj in objs
- if obj and 'external_link_href' in obj and 'external_link_display_name' in obj
+ if obj and obj.get('external_link_href') and obj.get('external_link_display_name')
))
return mark_safe(escape(super().display(logentry, data)) + "".join("
" + link + "
" for link in links))
@@ -522,6 +522,7 @@ def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, bl
'pretix.event.order.customer.changed': _('The customer account has been changed.'),
'pretix.event.order.locale.changed': _('The order locale has been changed.'),
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
+ 'pretix.event.order.invoice.failed': _('The invoice could not be generated.'),
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
'pretix.event.order.invoice.sent': _('The invoice {full_invoice_no} has been sent.'),
diff --git a/src/pretix/control/middleware.py b/src/pretix/control/middleware.py
index 9a176945d..9694e88de 100644
--- a/src/pretix/control/middleware.py
+++ b/src/pretix/control/middleware.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/navigation.py b/src/pretix/control/navigation.py
index 67bccaccd..99bdd8654 100644
--- a/src/pretix/control/navigation.py
+++ b/src/pretix/control/navigation.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/permissions.py b/src/pretix/control/permissions.py
index afc677ff2..059e2c9d3 100644
--- a/src/pretix/control/permissions.py
+++ b/src/pretix/control/permissions.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/signals.py b/src/pretix/control/signals.py
index afae6a2a9..504aa2a82 100644
--- a/src/pretix/control/signals.py
+++ b/src/pretix/control/signals.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/sysreport.py b/src/pretix/control/sysreport.py
index 0c86deb26..6beb0e4fc 100644
--- a/src/pretix/control/sysreport.py
+++ b/src/pretix/control/sysreport.py
@@ -1,8 +1,8 @@
#
# This file is part of pretix (Community Edition).
#
-# Copyright (C) 2014-2020 Raphael Michel and contributors
-# Copyright (C) 2020-2021 rami.io GmbH and contributors
+# 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.
diff --git a/src/pretix/control/templates/pretixcontrol/event/invoicing.html b/src/pretix/control/templates/pretixcontrol/event/invoicing.html
index d2b21e70e..52d9a7e9b 100644
--- a/src/pretix/control/templates/pretixcontrol/event/invoicing.html
+++ b/src/pretix/control/templates/pretixcontrol/event/invoicing.html
@@ -15,6 +15,19 @@
{% bootstrap_field form.invoice_email_attachment layout="control" %}
{% bootstrap_field form.invoice_email_organizer layout="control" %}
{% bootstrap_field form.invoice_language layout="control" %}
+ {% bootstrap_field form.invoice_period layout="control" %}
+
+ {% if not request.event.settings.show_dates_on_frontpage %}
+
+
+ {% blocktrans trimmed %}
+ You configured that your shop is not an event and the event date should not be shown.
+ Therefore, we recommend that you set the date of service to a different option.
+ {% endblocktrans %}
+