forked from CGM_Public/pretix_original
Compare commits
13 Commits
bundles-no
...
pdf-layout
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1263f4359f | ||
|
|
645df63e66 | ||
|
|
3416366763 | ||
|
|
bbefb59036 | ||
|
|
8f0a277c7b | ||
|
|
9dc38e42d8 | ||
|
|
bfd88d1496 | ||
|
|
be6bd501bd | ||
|
|
d160c9fd67 | ||
|
|
221f14cc21 | ||
|
|
1dda2eb4fb | ||
|
|
30f2e99020 | ||
|
|
8efe276ed0 |
@@ -51,7 +51,7 @@ Endpoints
|
||||
"results": [
|
||||
{
|
||||
"identifier": "web",
|
||||
"name": {
|
||||
"label": {
|
||||
"en": "Online shop"
|
||||
},
|
||||
"type": "web",
|
||||
@@ -88,7 +88,7 @@ Endpoints
|
||||
|
||||
{
|
||||
"identifier": "web",
|
||||
"name": {
|
||||
"label": {
|
||||
"en": "Online shop"
|
||||
},
|
||||
"type": "web",
|
||||
@@ -116,7 +116,7 @@ Endpoints
|
||||
|
||||
{
|
||||
"identifier": "api.custom",
|
||||
"name": {
|
||||
"label": {
|
||||
"en": "Custom integration"
|
||||
},
|
||||
"type": "api",
|
||||
@@ -133,7 +133,7 @@ Endpoints
|
||||
|
||||
{
|
||||
"identifier": "api.custom",
|
||||
"name": {
|
||||
"label": {
|
||||
"en": "Custom integration"
|
||||
},
|
||||
"type": "api",
|
||||
@@ -178,7 +178,7 @@ Endpoints
|
||||
|
||||
{
|
||||
"identifier": "web",
|
||||
"name": {
|
||||
"label": {
|
||||
"en": "Online shop"
|
||||
},
|
||||
"type": "web",
|
||||
|
||||
@@ -14,7 +14,7 @@ Core
|
||||
:members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types, notification,
|
||||
item_copy_data, register_sales_channel_types, register_global_settings, quota_availability, global_email_filter,
|
||||
register_ticket_secret_generators, gift_card_transaction_display,
|
||||
register_text_placeholders, register_mail_placeholders
|
||||
register_text_placeholders, register_mail_placeholders, device_info_updated
|
||||
|
||||
Order events
|
||||
""""""""""""
|
||||
|
||||
@@ -29,8 +29,8 @@ item_assignments list of objects Products this l
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
Layout endpoints
|
||||
----------------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/ticketlayouts/
|
||||
|
||||
@@ -268,5 +268,75 @@ Endpoints
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to delete this resource.
|
||||
|
||||
Ticket rendering endpoint
|
||||
-----------------------------
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/ticketpdfrenderer/render_batch/
|
||||
|
||||
With this API call, you can instruct the system to render a set of tickets into one combined PDF file. To specify
|
||||
which tickets to render, you need to submit a list of "parts". For every part, the following fields are supported:
|
||||
|
||||
* ``orderposition`` (``integer``, required): The ID of the order position to render.
|
||||
* ``override_channel`` (``string``, optional): The sales channel ID to be used for layout selection instead of the
|
||||
original channel of the order.
|
||||
* ``override_layout`` (``integer``, optional): The ticket layout ID to be used instead of the auto-selected one.
|
||||
|
||||
If your input parameters validate correctly, a ``202 Accepted`` status code is returned.
|
||||
The body points you to the download URL of the result. Running a ``GET`` request on that result URL will
|
||||
yield one of the following status codes:
|
||||
|
||||
* ``200 OK`` – The export succeeded. The body will be your resulting file. Might be large!
|
||||
* ``409 Conflict`` – Your export is still running. The body will be JSON with the structure ``{"status": "running"}``. ``status`` can be ``waiting`` before the task is actually being processed. Please retry, but wait at least one second before you do.
|
||||
* ``410 Gone`` – Running the export has failed permanently. The body will be JSON with the structure ``{"status": "failed", "message": "Error message"}``
|
||||
* ``404 Not Found`` – The export does not exist / is expired.
|
||||
|
||||
.. warning:: This endpoint is considered **experimental**. It might change at any time without prior notice.
|
||||
|
||||
.. note:: To avoid performance issues, a maximum number of 1000 parts is currently allowed.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/events/sampleconf/ticketpdfrenderer/render_batch/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"orderposition": 55412
|
||||
},
|
||||
{
|
||||
"orderposition": 55412,
|
||||
"override_channel": "web"
|
||||
},
|
||||
{
|
||||
"orderposition": 55412,
|
||||
"override_layout": 56
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"download": "https://pretix.eu/api/v1/organizers/bigevents/events/sampleconf/ticketpdfrenderer/download/29891ede-196f-4942-9e26-d055a36e98b8/3f279f13-c198-4137-b49b-9b360ce9fcce/"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:param event: The ``slug`` field of the event to fetch
|
||||
:statuscode 202: no error
|
||||
:statuscode 400: Invalid input options
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
|
||||
.. _here: https://github.com/pretix/pretix/blob/master/src/pretix/static/schema/pdf-layout.schema.json
|
||||
|
||||
@@ -88,16 +88,20 @@ class SalesChannelMigrationMixin:
|
||||
}
|
||||
|
||||
if data.get("all_sales_channels") and set(data["sales_channels"]) != all_channels:
|
||||
raise ValidationError(
|
||||
"If 'all_sales_channels' is set, the legacy attribute 'sales_channels' must not be set or set to "
|
||||
"the list of all sales channels."
|
||||
)
|
||||
raise ValidationError({
|
||||
"limit_sales_channels": [
|
||||
"If 'all_sales_channels' is set, the legacy attribute 'sales_channels' must not be set or set to "
|
||||
"the list of all sales channels."
|
||||
]
|
||||
})
|
||||
|
||||
if data.get("limit_sales_channels") and set(data["sales_channels"]) != set(data["limit_sales_channels"]):
|
||||
raise ValidationError(
|
||||
"If 'limit_sales_channels' is set, the legacy attribute 'sales_channels' must not be set or set to "
|
||||
"the same list."
|
||||
)
|
||||
raise ValidationError({
|
||||
"limit_sales_channels": [
|
||||
"If 'limit_sales_channels' is set, the legacy attribute 'sales_channels' must not be set or set to "
|
||||
"the same list."
|
||||
]
|
||||
})
|
||||
|
||||
if data["sales_channels"] == all_channels:
|
||||
data["all_sales_channels"] = True
|
||||
|
||||
@@ -200,6 +200,11 @@ class UpdateView(APIView):
|
||||
device.save()
|
||||
device.log_action('pretix.device.updated', data=serializer.validated_data, auth=device)
|
||||
|
||||
from ...base.signals import device_info_updated
|
||||
device_info_updated.send(
|
||||
sender=Device, old_device=request.auth, new_device=device
|
||||
)
|
||||
|
||||
serializer = DeviceSerializer(device)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
@@ -304,10 +304,21 @@ class TaxRule(LoggedModel):
|
||||
subtract_from_gross = Decimal('0.00')
|
||||
rate = adjust_rate
|
||||
|
||||
def _limit_subtract(base_price, subtract_from_gross):
|
||||
if not subtract_from_gross:
|
||||
return base_price
|
||||
if base_price >= Decimal('0.00'):
|
||||
# For positive prices, make sure they don't go negative because of bundles
|
||||
return max(Decimal('0.00'), base_price - subtract_from_gross)
|
||||
else:
|
||||
# If the price is already negative, we don't really care any more
|
||||
return base_price - subtract_from_gross
|
||||
|
||||
if rate == Decimal('0.00'):
|
||||
gross = _limit_subtract(base_price, subtract_from_gross)
|
||||
return TaxedPrice(
|
||||
net=max(Decimal('0.00'), base_price - subtract_from_gross),
|
||||
gross=max(Decimal('0.00'), base_price - subtract_from_gross),
|
||||
net=gross,
|
||||
gross=gross,
|
||||
tax=Decimal('0.00'),
|
||||
rate=rate,
|
||||
name=self.name,
|
||||
@@ -320,19 +331,14 @@ class TaxRule(LoggedModel):
|
||||
base_price_is = 'net'
|
||||
|
||||
if base_price_is == 'gross':
|
||||
if base_price >= Decimal('0.00'):
|
||||
# For positive prices, make sure they don't go negative because of bundles
|
||||
gross = max(Decimal('0.00'), base_price - subtract_from_gross)
|
||||
else:
|
||||
# If the price is already negative, we don't really care any more
|
||||
gross = base_price - subtract_from_gross
|
||||
gross = _limit_subtract(base_price, subtract_from_gross)
|
||||
net = round_decimal(gross - (gross * (1 - 100 / (100 + rate))),
|
||||
currency)
|
||||
elif base_price_is == 'net':
|
||||
net = base_price
|
||||
gross = round_decimal((net * (1 + rate / 100)), currency)
|
||||
if subtract_from_gross:
|
||||
gross -= subtract_from_gross
|
||||
gross = _limit_subtract(gross, subtract_from_gross)
|
||||
net = round_decimal(gross - (gross * (1 - 100 / (100 + rate))),
|
||||
currency)
|
||||
else:
|
||||
|
||||
@@ -838,3 +838,12 @@ is given as the first argument.
|
||||
|
||||
The ``sender`` keyword argument will contain the organizer.
|
||||
"""
|
||||
|
||||
device_info_updated = django.dispatch.Signal()
|
||||
"""
|
||||
Arguments: ``old_device``, ``new_device``
|
||||
|
||||
This signal is sent out each time the information for a Device is modified.
|
||||
Both the original and updated versions of the Device are included to allow
|
||||
receivers to see what has been updated.
|
||||
"""
|
||||
|
||||
@@ -94,7 +94,9 @@ def process_login(request, user, keep_logged_in):
|
||||
pretix_successful_logins.inc(1)
|
||||
handle_login_source(user, request)
|
||||
auth_login(request, user)
|
||||
request.session['pretix_auth_login_time'] = int(time.time())
|
||||
t = int(time.time())
|
||||
request.session['pretix_auth_login_time'] = t
|
||||
request.session['pretix_auth_last_used'] = t
|
||||
if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None):
|
||||
return redirect_to_url(next_url)
|
||||
return redirect('control:index')
|
||||
|
||||
@@ -39,7 +39,7 @@ from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.db.models import Exists, Max, OuterRef, Prefetch, Q, Subquery
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.http import Http404, HttpResponseNotAllowed, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
@@ -193,6 +193,9 @@ class CheckInListShow(EventPermissionRequiredMixin, PaginationMixin, CheckInList
|
||||
class CheckInListBulkRevertConfirmView(CheckInListQueryMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
template_name = "pretixcontrol/checkin/bulk_revert_confirm.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return HttpResponseNotAllowed(permitted_methods=["POST"])
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.list = get_object_or_404(self.request.event.checkin_lists.all(), pk=kwargs.get("list"))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-09-26 11:22+0000\n"
|
||||
"PO-Revision-Date: 2024-10-02 17:00+0000\n"
|
||||
"PO-Revision-Date: 2024-10-10 07:00+0000\n"
|
||||
"Last-Translator: Patrick Chilton <chpatrick@gmail.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"hu/>\n"
|
||||
@@ -3048,7 +3048,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/forms/questions.py:1144
|
||||
msgid "You need to provide a company name."
|
||||
msgstr ""
|
||||
msgstr "Meg kell adnod céget."
|
||||
|
||||
#: pretix/base/forms/questions.py:1146
|
||||
msgid "You need to provide your name."
|
||||
@@ -3149,7 +3149,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/forms/widgets.py:234 pretix/base/forms/widgets.py:239
|
||||
msgid "Business or institutional customer"
|
||||
msgstr ""
|
||||
msgstr "Cég"
|
||||
|
||||
#: pretix/base/forms/widgets.py:238
|
||||
msgid "Individual customer"
|
||||
@@ -3942,7 +3942,7 @@ msgstr ""
|
||||
#: pretix/base/models/customers.py:299 pretix/base/models/orders.py:1513
|
||||
#: pretix/base/models/orders.py:3175 pretix/base/settings.py:1096
|
||||
msgid "Company name"
|
||||
msgstr ""
|
||||
msgstr "Cég"
|
||||
|
||||
#: pretix/base/models/customers.py:303 pretix/base/models/orders.py:1517
|
||||
#: pretix/base/models/orders.py:3182 pretix/base/settings.py:81
|
||||
@@ -5734,7 +5734,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:3190
|
||||
msgid "This reference will be printed on your invoice for your convenience."
|
||||
msgstr ""
|
||||
msgstr "Ezt a megjegyzést feltüntetjük neked a számlán."
|
||||
|
||||
#: pretix/base/models/organizer.py:79
|
||||
msgid ""
|
||||
@@ -7972,7 +7972,7 @@ msgstr ""
|
||||
#: pretix/base/services/orders.py:561 pretix/control/forms/orders.py:205
|
||||
msgid ""
|
||||
"The cancellation fee cannot be higher than the total amount of this order."
|
||||
msgstr ""
|
||||
msgstr "A lemondási díj nem lehet magasabb a rendelés áránál."
|
||||
|
||||
#: pretix/base/services/orders.py:955
|
||||
#, fuzzy
|
||||
@@ -16058,7 +16058,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:30
|
||||
msgctxt "terminal_zvt"
|
||||
msgid "Card type"
|
||||
msgstr ""
|
||||
msgstr "Kártytípus"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:37
|
||||
#, fuzzy
|
||||
@@ -16095,7 +16095,7 @@ msgstr ""
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_card.html:31
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:14
|
||||
msgid "Card number"
|
||||
msgstr ""
|
||||
msgstr "Kártyaszám"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:65
|
||||
msgid "Client Transaction Code"
|
||||
@@ -26626,6 +26626,8 @@ msgid ""
|
||||
"The total amount listed above will be withdrawn from your PayPal account "
|
||||
"after the confirmation of your purchase."
|
||||
msgstr ""
|
||||
"A teljes összeg levonásra kerül a PayPal fiókodról miután megerősítjük a "
|
||||
"rendelésedet."
|
||||
|
||||
#: pretix/plugins/paypal/templates/pretixplugins/paypal/checkout_payment_form.html:3
|
||||
msgid ""
|
||||
@@ -28457,11 +28459,11 @@ msgstr ""
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_card.html:29
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:12
|
||||
msgid "Card type"
|
||||
msgstr ""
|
||||
msgstr "Kártyatípus"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:14
|
||||
msgid "The total amount will be withdrawn from your bank account."
|
||||
msgstr ""
|
||||
msgstr "A teljes összeg levonásra kerül a bankszámládról."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:18
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:23
|
||||
@@ -28510,6 +28512,8 @@ msgid ""
|
||||
"Your payment will be processed by Stripe, Inc. Your credit card data will be "
|
||||
"transmitted directly to Stripe and never touches our servers."
|
||||
msgstr ""
|
||||
"A fizetésedet a Stripe fogja feldolgozni. A kártyaadataid egyenesen a Stripe-"
|
||||
"hoz mennek és nem érintik a szervereinket."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:13
|
||||
msgid "For a SEPA Debit payment, please turn on JavaScript."
|
||||
@@ -28874,7 +28878,7 @@ msgstr ""
|
||||
#: pretix/presale/checkoutflow.py:717
|
||||
msgctxt "checkoutflow"
|
||||
msgid "Your information"
|
||||
msgstr ""
|
||||
msgstr "Az adataid"
|
||||
|
||||
#: pretix/presale/checkoutflow.py:943
|
||||
msgid ""
|
||||
@@ -28906,7 +28910,7 @@ msgstr ""
|
||||
#: pretix/presale/checkoutflow.py:1202
|
||||
msgctxt "checkoutflow"
|
||||
msgid "Payment"
|
||||
msgstr ""
|
||||
msgstr "Fizetés"
|
||||
|
||||
#: pretix/presale/checkoutflow.py:1315
|
||||
msgid ""
|
||||
@@ -28931,7 +28935,7 @@ msgstr ""
|
||||
#: pretix/presale/checkoutflow.py:1442
|
||||
msgctxt "checkoutflow"
|
||||
msgid "Review order"
|
||||
msgstr ""
|
||||
msgstr "Rendelés ellenőrzése"
|
||||
|
||||
#: pretix/presale/checkoutflow.py:1536
|
||||
msgid "You need to check all checkboxes on the bottom of the page."
|
||||
@@ -30630,7 +30634,7 @@ msgstr "Számlaigénylés"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:286
|
||||
msgid "Your information"
|
||||
msgstr "Személyes adatok"
|
||||
msgstr "Az adataid"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:289
|
||||
msgid "Change your information"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-09-26 11:22+0000\n"
|
||||
"PO-Revision-Date: 2024-09-30 05:00+0000\n"
|
||||
"Last-Translator: Rosariocastellana <rosariocastellana@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-10-08 18:00+0000\n"
|
||||
"Last-Translator: Davide Manzella <manzella.davide97@gmail.com>\n"
|
||||
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"it/>\n"
|
||||
"Language: it\n"
|
||||
@@ -178,10 +178,8 @@ msgid "Allowed URIs list, space separated"
|
||||
msgstr "Lista delle URI autorizzate, separate da spazio"
|
||||
|
||||
#: pretix/api/models.py:47
|
||||
#, fuzzy
|
||||
#| msgid "Allowed URIs list, space separated"
|
||||
msgid "Allowed Post Logout URIs list, space separated"
|
||||
msgstr "Lista delle URI autorizzate, separate da spazio"
|
||||
msgstr "Lista delle URI Dopo Logout autorizzate, separate da spazio"
|
||||
|
||||
#: pretix/api/models.py:51 pretix/base/models/customers.py:395
|
||||
#: pretix/plugins/paypal/payment.py:113 pretix/plugins/paypal2/payment.py:110
|
||||
@@ -264,10 +262,9 @@ msgid "Unknown plugin: '{name}'."
|
||||
msgstr "Plugin sconosciuto: '{name}'."
|
||||
|
||||
#: pretix/api/serializers/event.py:295
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Unknown plugin: '{name}'."
|
||||
#, python-brace-format
|
||||
msgid "Restricted plugin: '{name}'."
|
||||
msgstr "Plugin sconosciuto: '{name}'."
|
||||
msgstr "Plugin a cui è limitato l'accesso: '{name}'."
|
||||
|
||||
#: pretix/api/serializers/item.py:86 pretix/api/serializers/item.py:148
|
||||
#: pretix/api/serializers/item.py:359
|
||||
@@ -332,8 +329,6 @@ msgid "This type of question cannot be asked during check-in."
|
||||
msgstr "Questo tipo di domanda non può essere fatta durante il check-in."
|
||||
|
||||
#: pretix/api/serializers/item.py:531 pretix/control/forms/item.py:142
|
||||
#, fuzzy
|
||||
#| msgid "This type of question cannot be asked during check-in."
|
||||
msgid "This type of question cannot be shown during check-in."
|
||||
msgstr "Questo tipo di domanda non può essere fatta durante il check-in."
|
||||
|
||||
@@ -402,7 +397,7 @@ msgstr ""
|
||||
|
||||
#: pretix/api/views/checkin.py:604 pretix/api/views/checkin.py:611
|
||||
msgid "Medium connected to other event"
|
||||
msgstr ""
|
||||
msgstr "Medium connesso ad un altro evento"
|
||||
|
||||
#: pretix/api/views/oauth.py:107 pretix/control/logdisplay.py:475
|
||||
#, python-brace-format
|
||||
@@ -515,10 +510,8 @@ msgid "Order denied"
|
||||
msgstr "Ordine rifiutato"
|
||||
|
||||
#: pretix/api/webhooks.py:313
|
||||
#, fuzzy
|
||||
#| msgid "Order denied"
|
||||
msgid "Order deleted"
|
||||
msgstr "Ordine rifiutato"
|
||||
msgstr "Ordine cancellato"
|
||||
|
||||
#: pretix/api/webhooks.py:317
|
||||
msgid "Ticket checked in"
|
||||
@@ -580,9 +573,8 @@ msgid "Test-Mode of shop has been deactivated"
|
||||
msgstr "La modalità test del negozio è stata disattivata"
|
||||
|
||||
#: pretix/api/webhooks.py:370
|
||||
#, fuzzy
|
||||
msgid "Waiting list entry added"
|
||||
msgstr "Lista d'attesa"
|
||||
msgstr "Inserito correttamente nella lista d'attesa"
|
||||
|
||||
#: pretix/api/webhooks.py:374
|
||||
msgid "Waiting list entry changed"
|
||||
@@ -659,7 +651,7 @@ msgstr "Password"
|
||||
|
||||
#: pretix/base/auth.py:176 pretix/base/auth.py:183
|
||||
msgid "Your password must contain both numeric and alphabetic characters."
|
||||
msgstr ""
|
||||
msgstr "La password deve contenere sia caratteri numerici che alfabetici."
|
||||
|
||||
#: pretix/base/auth.py:202 pretix/base/auth.py:212
|
||||
#, python-format
|
||||
@@ -667,8 +659,9 @@ msgid "Your password may not be the same as your previous password."
|
||||
msgid_plural ""
|
||||
"Your password may not be the same as one of your %(history_length)s previous "
|
||||
"passwords."
|
||||
msgstr[0] ""
|
||||
msgstr[0] "La password non può essere uguale a quella che si vuole cambiare."
|
||||
msgstr[1] ""
|
||||
"La password non può essere uguale ad una delle %(history_length)s precedenti."
|
||||
|
||||
#: pretix/base/channels.py:168
|
||||
msgid "Online shop"
|
||||
@@ -676,13 +669,15 @@ msgstr "Vendite online"
|
||||
|
||||
#: pretix/base/channels.py:174
|
||||
msgid "API"
|
||||
msgstr ""
|
||||
msgstr "API"
|
||||
|
||||
#: pretix/base/channels.py:175
|
||||
msgid ""
|
||||
"API sales channels come with no built-in functionality, but may be used for "
|
||||
"custom integrations."
|
||||
msgstr ""
|
||||
"API per i canali di vendita senza funzionalità incorporate, ma può essere "
|
||||
"usata per integrazioni personalizzate."
|
||||
|
||||
#: pretix/base/context.py:45
|
||||
#, python-brace-format
|
||||
@@ -746,6 +741,8 @@ msgid ""
|
||||
"No supported Token Endpoint Auth Methods supported: "
|
||||
"{token_endpoint_auth_methods_supported}"
|
||||
msgstr ""
|
||||
"Nessun metodo di autenticazione di tipo Token per Endpoint supportatp: "
|
||||
"{token_endpoint_auth_methods_supported}"
|
||||
|
||||
#: pretix/base/customersso/oidc.py:203 pretix/base/customersso/oidc.py:210
|
||||
#: pretix/base/customersso/oidc.py:229 pretix/base/customersso/oidc.py:246
|
||||
@@ -1089,7 +1086,6 @@ msgid "No"
|
||||
msgstr "No"
|
||||
|
||||
#: pretix/base/exporters/dekodi.py:42 pretix/base/exporters/invoices.py:66
|
||||
#, fuzzy
|
||||
msgctxt "export_category"
|
||||
msgid "Invoices"
|
||||
msgstr "Fatture"
|
||||
@@ -1616,7 +1612,6 @@ msgid "Product data"
|
||||
msgstr "Dati del prodotto"
|
||||
|
||||
#: pretix/base/exporters/items.py:50 pretix/base/exporters/orderlist.py:1128
|
||||
#, fuzzy
|
||||
msgctxt "export_category"
|
||||
msgid "Product data"
|
||||
msgstr "Dati del prodotto"
|
||||
@@ -1800,9 +1795,8 @@ msgstr "Richiede particolare attenzione"
|
||||
#: pretix/base/modelimport_orders.py:617 pretix/base/models/items.py:614
|
||||
#: pretix/base/models/items.py:1197 pretix/base/models/orders.py:287
|
||||
#: pretix/plugins/checkinlists/exporters.py:522
|
||||
#, fuzzy
|
||||
msgid "Check-in text"
|
||||
msgstr "Checkout"
|
||||
msgstr "Testo di Check-in"
|
||||
|
||||
#: pretix/base/exporters/items.py:91 pretix/base/models/items.py:619
|
||||
#: pretix/base/models/items.py:1117
|
||||
@@ -2319,10 +2313,8 @@ msgid "Order comment"
|
||||
msgstr "Commento all'ordine"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:622
|
||||
#, fuzzy
|
||||
#| msgid "Position ID"
|
||||
msgid "Add-on to position ID"
|
||||
msgstr "ID Posizione"
|
||||
msgstr "Add-on al ID Posizione"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:650 pretix/base/pdf.py:340
|
||||
msgid "Invoice address street"
|
||||
@@ -2353,7 +2345,7 @@ msgstr "Nazione di fatturazione"
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html:162
|
||||
#: pretix/plugins/checkinlists/apps.py:44
|
||||
msgid "Check-in lists"
|
||||
msgstr ""
|
||||
msgstr "Liste de Check-in"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:822
|
||||
msgid "Order transaction data"
|
||||
@@ -2553,9 +2545,8 @@ msgid "Payment method"
|
||||
msgstr "Metodo di pagamento"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1077
|
||||
#, fuzzy
|
||||
msgid "Matching ID"
|
||||
msgstr "ID Pagamento"
|
||||
msgstr "ID Combaciato"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1077
|
||||
#: pretix/control/templates/pretixcontrol/order/refund_choose.html:38
|
||||
@@ -2620,7 +2611,6 @@ msgstr "Transazioni con carta regalo"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1183
|
||||
#: pretix/base/exporters/orderlist.py:1288
|
||||
#, fuzzy
|
||||
msgctxt "export_category"
|
||||
msgid "Gift cards"
|
||||
msgstr "Carte regalo"
|
||||
@@ -2822,34 +2812,29 @@ msgstr "Ultima data di fatturazione dell'ordine"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html:6
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html:9
|
||||
msgid "Reusable media"
|
||||
msgstr ""
|
||||
msgstr "Media Riutilizzabile"
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:35
|
||||
msgctxt "export_category"
|
||||
msgid "Reusable media"
|
||||
msgstr ""
|
||||
msgstr "Media Riutilizzabile"
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:36
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Download a spreadsheet with information on all events in this organizer "
|
||||
#| "account."
|
||||
msgid ""
|
||||
"Download a spread sheet with the data of all reusable medias on your account."
|
||||
msgstr ""
|
||||
"Scarica un foglio di calcolo con le informazioni su tutti gli eventi di "
|
||||
"questo account organizzatore."
|
||||
"Scarica un foglio di calcolo con le informazioni con i dati di tutti i media "
|
||||
"riutlizzabili dell' account."
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:46 pretix/base/models/media.py:67
|
||||
#, fuzzy
|
||||
msgctxt "reusable_medium"
|
||||
msgid "Media type"
|
||||
msgstr "Tipo di tariffa"
|
||||
msgstr "Tipo di Media"
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:47 pretix/base/models/media.py:73
|
||||
msgctxt "reusable_medium"
|
||||
msgid "Identifier"
|
||||
msgstr ""
|
||||
msgstr "Identificativo"
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:49 pretix/base/models/media.py:81
|
||||
#: pretix/base/models/orders.py:263 pretix/base/models/orders.py:3014
|
||||
@@ -2861,22 +2846,18 @@ msgstr "Data di scadenza"
|
||||
#: pretix/base/exporters/reusablemedia.py:50 pretix/base/models/media.py:90
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html:215
|
||||
#: pretix/presale/templates/pretixpresale/event/checkout_confirm.html:132
|
||||
#, fuzzy
|
||||
msgid "Customer account"
|
||||
msgstr "Domande"
|
||||
msgstr "Account del cliente"
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:51 pretix/base/models/media.py:97
|
||||
#, fuzzy
|
||||
msgid "Linked ticket"
|
||||
msgstr "Testo footer aggiuntivo"
|
||||
msgstr "Ticket collegato"
|
||||
|
||||
#: pretix/base/exporters/reusablemedia.py:52 pretix/base/models/media.py:104
|
||||
#, fuzzy
|
||||
msgid "Linked gift card"
|
||||
msgstr "Pagato con carta regalo"
|
||||
msgstr "Carta regalo collegata"
|
||||
|
||||
#: pretix/base/exporters/waitinglist.py:42
|
||||
#, fuzzy
|
||||
msgctxt "export_category"
|
||||
msgid "Waiting list"
|
||||
msgstr "Lista d'attesa"
|
||||
@@ -2955,7 +2936,7 @@ msgstr "Codice del voucher"
|
||||
#: pretix/base/forms/__init__.py:118
|
||||
#, python-brace-format
|
||||
msgid "You can use {markup_name} in this field."
|
||||
msgstr ""
|
||||
msgstr "Puoi usare {markup_name} in questo campo."
|
||||
|
||||
#: pretix/base/forms/__init__.py:178
|
||||
#, python-format
|
||||
@@ -3169,12 +3150,15 @@ msgid ""
|
||||
"up. Please note: to use literal \"{\" or \"}\", you need to double them as "
|
||||
"\"{{\" and \"}}\"."
|
||||
msgstr ""
|
||||
"è presente un errore nella sintassi dei placeholder. Controllare che le "
|
||||
"graffe di apertura \"{\" e di chiusura \"}\" sui placeholder match up. Fare "
|
||||
"attenzione: perutlizzare \"{\" oppure \"}\", è necessario raddoppiarli \"{{ "
|
||||
"e \"}}\"."
|
||||
|
||||
#: pretix/base/forms/validators.py:72 pretix/control/views/event.py:763
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Invalid placeholder(s): %(value)s"
|
||||
#, python-format
|
||||
msgid "Invalid placeholder: {%(value)s}"
|
||||
msgstr "Placeholder(s) non valido: %(value)s"
|
||||
msgstr "Placeholder non valido: %(value)s"
|
||||
|
||||
#: pretix/base/forms/widgets.py:68
|
||||
#, python-format
|
||||
@@ -3191,7 +3175,7 @@ msgstr "Segnalibri disponibili: {list}"
|
||||
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html:40
|
||||
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html:54
|
||||
msgid "Time"
|
||||
msgstr ""
|
||||
msgstr "Orario"
|
||||
|
||||
#: pretix/base/forms/widgets.py:234 pretix/base/forms/widgets.py:239
|
||||
msgid "Business or institutional customer"
|
||||
@@ -3420,7 +3404,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/invoice.py:858
|
||||
msgid "Default invoice renderer (European-style letter)"
|
||||
msgstr ""
|
||||
msgstr "Renderizzatore di fatture di default (Stile Europeo)"
|
||||
|
||||
#: pretix/base/invoice.py:947
|
||||
msgctxt "invoice"
|
||||
@@ -3429,15 +3413,13 @@ msgstr "(Per cortesia citare sempre.)"
|
||||
|
||||
#: pretix/base/invoice.py:994
|
||||
msgid "Simplified invoice renderer"
|
||||
msgstr ""
|
||||
msgstr "Renderizzatore di fatture semplificato"
|
||||
|
||||
#: pretix/base/invoice.py:1013
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "Event series date changed"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Event date: {date_range}"
|
||||
msgstr "Serie di date modificate"
|
||||
msgstr "Data evento: {date_range}"
|
||||
|
||||
#: pretix/base/media.py:61
|
||||
msgid "Barcode / QR-Code"
|
||||
@@ -3455,58 +3437,57 @@ msgstr "Lista predefinita"
|
||||
|
||||
#: pretix/base/modelimport.py:112
|
||||
msgid "Keep empty"
|
||||
msgstr ""
|
||||
msgstr "Lasciare vuoto"
|
||||
|
||||
#: pretix/base/modelimport.py:139
|
||||
#, python-brace-format
|
||||
msgid "Invalid setting for column \"{header}\"."
|
||||
msgstr ""
|
||||
msgstr "Settaggio invalido per colonna \"{header}\"."
|
||||
|
||||
#: pretix/base/modelimport.py:199
|
||||
#, python-brace-format
|
||||
msgid "Could not parse {value} as a yes/no value."
|
||||
msgstr ""
|
||||
msgstr "Non è stato possibile leggere {value} come valore di sì/no."
|
||||
|
||||
#: pretix/base/modelimport.py:222
|
||||
#, python-brace-format
|
||||
msgid "Could not parse {value} as a date and time."
|
||||
msgstr ""
|
||||
msgstr "Non è stato possibile leggere {value} come data e ora."
|
||||
|
||||
#: pretix/base/modelimport.py:232 pretix/control/views/orders.py:1161
|
||||
#: pretix/control/views/orders.py:1190 pretix/control/views/orders.py:1234
|
||||
#: pretix/control/views/orders.py:1269 pretix/control/views/orders.py:1292
|
||||
msgid "You entered an invalid number."
|
||||
msgstr ""
|
||||
msgstr "Hai inserito un numero invalido."
|
||||
|
||||
#: pretix/base/modelimport.py:276 pretix/base/modelimport.py:288
|
||||
msgctxt "subevent"
|
||||
msgid "No matching date was found."
|
||||
msgstr ""
|
||||
msgstr "Nessuna data combaciante è stata trovata."
|
||||
|
||||
#: pretix/base/modelimport.py:278 pretix/base/modelimport.py:290
|
||||
msgctxt "subevent"
|
||||
msgid "Multiple matching dates were found."
|
||||
msgstr ""
|
||||
msgstr "Molteplici date che combaciano sono state trovate."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:85
|
||||
#, fuzzy
|
||||
msgid "Enter a valid phone number."
|
||||
msgstr "Numero di telefono"
|
||||
msgstr "Inserire un numero di telefono valido."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:100 pretix/presale/views/waiting.py:118
|
||||
msgctxt "subevent"
|
||||
msgid "You need to select a date."
|
||||
msgstr ""
|
||||
msgstr "Devi selezionare una data."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:128
|
||||
#: pretix/base/modelimport_vouchers.py:194
|
||||
msgid "No matching product was found."
|
||||
msgstr ""
|
||||
msgstr "Nessun prodotto combaciante è stato trovato."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:130
|
||||
#: pretix/base/modelimport_vouchers.py:196
|
||||
msgid "Multiple matching products were found."
|
||||
msgstr ""
|
||||
msgstr "Molteplici prodotti combacianti sono stati trovati."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:139
|
||||
#: pretix/base/modelimport_vouchers.py:205 pretix/base/models/items.py:1205
|
||||
@@ -3518,13 +3499,13 @@ msgstr "Variante prodotto"
|
||||
#: pretix/base/modelimport_vouchers.py:225
|
||||
#: pretix/base/modelimport_vouchers.py:259
|
||||
msgid "No matching variation was found."
|
||||
msgstr ""
|
||||
msgstr "Nessuna variazione combaciante trovata."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:161
|
||||
#: pretix/base/modelimport_vouchers.py:227
|
||||
#: pretix/base/modelimport_vouchers.py:261
|
||||
msgid "Multiple matching variations were found."
|
||||
msgstr ""
|
||||
msgstr "Multiple variazioni combacianti trovate."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:164
|
||||
msgid "You need to select a variation for this product."
|
||||
@@ -3543,15 +3524,15 @@ msgstr "Indirizzo di fatturazione"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:251 pretix/base/modelimport_orders.py:397
|
||||
msgid "Please enter a valid country code."
|
||||
msgstr ""
|
||||
msgstr "Inserire un codice prefisso del paese valido."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:268 pretix/base/modelimport_orders.py:414
|
||||
msgid "States are not supported for this country."
|
||||
msgstr ""
|
||||
msgstr "Stati non sono supportati per questa nazione."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:276 pretix/base/modelimport_orders.py:422
|
||||
msgid "Please enter a valid state."
|
||||
msgstr ""
|
||||
msgstr "Inserire uno stato valido."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:325 pretix/control/forms/filter.py:651
|
||||
msgid "Attendee e-mail address"
|
||||
@@ -3575,7 +3556,7 @@ msgstr "Stato"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:432
|
||||
msgid "Calculate from product"
|
||||
msgstr ""
|
||||
msgstr "Calculare dal prodotto"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:449
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html:111
|
||||
@@ -3585,29 +3566,29 @@ msgstr "Codice biglietto"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:450
|
||||
msgid "Generate automatically"
|
||||
msgstr ""
|
||||
msgstr "Generare automaticamente"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:459
|
||||
msgid "You cannot assign a position secret that already exists."
|
||||
msgstr ""
|
||||
msgstr "Non è possibile assegnare un segreto di posizione preesistente."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:490
|
||||
msgid "Please enter a valid language code."
|
||||
msgstr ""
|
||||
msgstr "Inserire un codice linguaggio valido."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560
|
||||
msgid "Please enter a valid sales channel."
|
||||
msgstr ""
|
||||
msgstr "Inserire un valido canale di vendita."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:584
|
||||
#: pretix/base/modelimport_vouchers.py:291
|
||||
msgid "Multiple matching seats were found."
|
||||
msgstr ""
|
||||
msgstr "Molteplici posti a sedere trovati."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:586
|
||||
#: pretix/base/modelimport_vouchers.py:293
|
||||
msgid "No matching seat was found."
|
||||
msgstr ""
|
||||
msgstr "Nessun posto a sedere trovato."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:589
|
||||
#: pretix/base/modelimport_vouchers.py:296 pretix/base/services/cart.py:212
|
||||
@@ -3616,10 +3597,12 @@ msgstr ""
|
||||
msgid ""
|
||||
"The seat you selected has already been taken. Please select a different seat."
|
||||
msgstr ""
|
||||
"Il posto a sedere da lei selezionato è stato già preso. Per piacere "
|
||||
"selezionare un posto a sedere differente."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:592 pretix/base/services/cart.py:209
|
||||
msgid "You need to select a specific seat."
|
||||
msgstr ""
|
||||
msgstr "è necessario selezionare un posto a sedere specifico."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:646 pretix/base/models/items.py:1618
|
||||
#: pretix/base/models/items.py:1713 pretix/control/forms/item.py:91
|
||||
@@ -3627,16 +3610,16 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/question_edit.html:17
|
||||
#: pretix/control/templates/pretixcontrol/items/questions.html:21
|
||||
msgid "Question"
|
||||
msgstr ""
|
||||
msgstr "Domanda"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:656 pretix/base/modelimport_orders.py:664
|
||||
#: pretix/base/models/items.py:1777 pretix/base/models/items.py:1795
|
||||
msgid "Invalid option selected."
|
||||
msgstr ""
|
||||
msgstr "L' opzione selezionata è invalida."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:658 pretix/base/modelimport_orders.py:666
|
||||
msgid "Ambiguous option selected."
|
||||
msgstr ""
|
||||
msgstr "L'opzione selezionata è ambigua."
|
||||
|
||||
#: pretix/base/modelimport_orders.py:697 pretix/base/models/orders.py:237
|
||||
#: pretix/control/forms/orders.py:643 pretix/control/forms/organizer.py:784
|
||||
@@ -3645,48 +3628,49 @@ msgstr "Cliente"
|
||||
|
||||
#: pretix/base/modelimport_orders.py:710
|
||||
msgid "No matching customer was found."
|
||||
msgstr ""
|
||||
msgstr "Nessun cliente ciìombaciante è stato trovato."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:50 pretix/base/models/vouchers.py:488
|
||||
msgid "A voucher with this code already exists."
|
||||
msgstr ""
|
||||
msgstr "Un voucher con questo codice esiste già."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:68 pretix/base/models/memberships.py:57
|
||||
#: pretix/base/models/vouchers.py:196 pretix/control/views/vouchers.py:120
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:28
|
||||
msgid "Maximum usages"
|
||||
msgstr ""
|
||||
msgstr "Massimi utlizzi"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:79
|
||||
msgid "The maximum number of usages must be set."
|
||||
msgstr ""
|
||||
msgstr "Il massimo numero di ultizzi deve essere configurato."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:88 pretix/base/models/vouchers.py:205
|
||||
#, fuzzy
|
||||
msgid "Minimum usages"
|
||||
msgstr "Utilizzi massimi per voucher"
|
||||
msgstr "Mini utlizzi"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:103 pretix/base/models/vouchers.py:213
|
||||
msgid "Maximum discount budget"
|
||||
msgstr ""
|
||||
msgstr "Massimo discount budget"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:119 pretix/base/models/vouchers.py:225
|
||||
#: pretix/control/forms/filter.py:2106
|
||||
msgid "Reserve ticket from quota"
|
||||
msgstr ""
|
||||
msgstr "Prenotare biglietto dalla quota disponibile"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:127 pretix/base/models/vouchers.py:233
|
||||
msgid "Allow to bypass quota"
|
||||
msgstr ""
|
||||
msgstr "Permettere di superare la quota"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:135 pretix/base/models/vouchers.py:239
|
||||
msgid "Price mode"
|
||||
msgstr ""
|
||||
msgstr "Modalità prezzo"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:150
|
||||
#, python-brace-format
|
||||
msgid "Could not parse {value} as a price mode, use one of {options}."
|
||||
msgstr ""
|
||||
"Non è possible leggere {value} come modalità prezzo, usare una delle "
|
||||
"{options}."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:160 pretix/base/models/vouchers.py:245
|
||||
msgid "Voucher value"
|
||||
@@ -3694,56 +3678,64 @@ msgstr "Valore Voucher"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:165
|
||||
msgid "It is pointless to set a value without a price mode."
|
||||
msgstr ""
|
||||
msgstr "è inutile settare un valore senza modalità prezzo."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:237 pretix/base/models/items.py:2040
|
||||
#: pretix/base/models/vouchers.py:272
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_edit.html:8
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_edit.html:15
|
||||
msgid "Quota"
|
||||
msgstr ""
|
||||
msgstr "Quota"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:253
|
||||
msgid "You cannot specify a quota if you specified a product."
|
||||
msgstr ""
|
||||
msgstr "Non è possiblile specificare una quota se hai specificato un prodotto."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:282 pretix/base/models/vouchers.py:495
|
||||
msgid "You need to choose a date if you select a seat."
|
||||
msgstr ""
|
||||
msgstr "è necessario scegliere una data se si seleziona un posto a sedere."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:299 pretix/base/models/vouchers.py:513
|
||||
msgid "You need to choose a specific product if you select a seat."
|
||||
msgstr ""
|
||||
"è necessario scegliere un prodotto specifico se si seleziona un posto a "
|
||||
"sedere."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:302 pretix/base/models/vouchers.py:516
|
||||
msgid "Seat-specific vouchers can only be used once."
|
||||
msgstr ""
|
||||
"Voucher specifici per un posto a sedere possono essere usati solo una volta "
|
||||
"sola."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:306 pretix/base/models/vouchers.py:519
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
msgid "You need to choose the product \"{prod}\" for this seat."
|
||||
msgstr ""
|
||||
"è necessario sceglliere il prodotto \"[prod}\" per questo posto a sedere."
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:318 pretix/base/models/vouchers.py:285
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html:129
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/tags.html:42
|
||||
#: pretix/control/views/vouchers.py:120
|
||||
msgid "Tag"
|
||||
msgstr ""
|
||||
msgstr "Etichetta"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:334 pretix/base/models/vouchers.py:297
|
||||
msgid "Shows hidden products that match this voucher"
|
||||
msgstr ""
|
||||
msgstr "Mostrare i prodotti nascoscti che combaciano con questo voucher"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:343 pretix/base/models/vouchers.py:301
|
||||
msgid "Offer all add-on products for free when redeeming this voucher"
|
||||
msgstr ""
|
||||
"Offrire tutti i prodotti add-on gratuitamente riscattando questo voucher"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py:351 pretix/base/models/vouchers.py:305
|
||||
msgid ""
|
||||
"Include all bundled products without a designated price when redeeming this "
|
||||
"voucher"
|
||||
msgstr ""
|
||||
"Includere tutti i prodotti inclusi nel pacchetto senza un prezzo quando "
|
||||
"riscatti questo voucher"
|
||||
|
||||
#: pretix/base/models/auth.py:248
|
||||
msgid "Is active"
|
||||
@@ -3824,18 +3816,21 @@ msgstr ""
|
||||
#: pretix/base/models/checkin.py:65
|
||||
msgctxt "checkin"
|
||||
msgid "Ignore check-ins on this list in statistics"
|
||||
msgstr ""
|
||||
msgstr "Ignora check-in presenti in questa lista, per le statistiche"
|
||||
|
||||
#: pretix/base/models/checkin.py:69
|
||||
msgctxt "checkin"
|
||||
msgid "Tickets with a check-in on this list should be considered \"used\""
|
||||
msgstr ""
|
||||
"Biglietti con un check-in in questa lista sono da considerarsi \"usati\""
|
||||
|
||||
#: pretix/base/models/checkin.py:70
|
||||
msgid ""
|
||||
"This is relevant in various situations, e.g. for deciding if a ticket can "
|
||||
"still be canceled by the customer."
|
||||
msgstr ""
|
||||
"Questo è rilevante in varie situazioni, ad esempio per devidere se un "
|
||||
"biglietto può ancora essere cancellato dal cliente."
|
||||
|
||||
#: pretix/base/models/checkin.py:74
|
||||
msgctxt "checkin"
|
||||
@@ -3908,6 +3903,10 @@ msgid ""
|
||||
"replacement, our new plugin \"Auto check-in\" can be used. When we remove "
|
||||
"this option, we will automatically migrate your event to use the new plugin."
|
||||
msgstr ""
|
||||
"Questa opzione è deprecata e verra rimossa nei mesi seguenti. Come "
|
||||
"rimpiazzo, il nuovo plugin \"Auto check-in\" può essere usato. Quando verra "
|
||||
"rimossa questa opzione, migreremo automaticamente il tuo evento nell' "
|
||||
"utilizzo del nuovo plugin."
|
||||
|
||||
#: pretix/base/models/checkin.py:340
|
||||
msgid "Entry"
|
||||
@@ -4293,15 +4292,18 @@ msgid ""
|
||||
"Optional. No products will be sold after this date. If you do not set this "
|
||||
"value, the presale will end after the end date of your event."
|
||||
msgstr ""
|
||||
"Opzionale. nessun prodotto verrà venduto oltre questa data. Se questo campo "
|
||||
"non viene settato, il periodo di prevendita finirà dopo la data di fine "
|
||||
"evento."
|
||||
|
||||
#: pretix/base/models/event.py:599 pretix/base/models/event.py:1480
|
||||
#: pretix/control/forms/subevents.py:94
|
||||
msgid "Optional. No products will be sold before this date."
|
||||
msgstr ""
|
||||
msgstr "Opzionale. Nessun prodotto verrà venduto rima di questa data."
|
||||
|
||||
#: pretix/base/models/event.py:624 pretix/control/navigation.py:65
|
||||
msgid "Plugins"
|
||||
msgstr ""
|
||||
msgstr "Plugin"
|
||||
|
||||
#: pretix/base/models/event.py:631 pretix/base/pdf.py:229
|
||||
#: pretix/control/forms/event.py:260 pretix/control/forms/filter.py:1677
|
||||
@@ -4311,11 +4313,11 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html:90
|
||||
#: pretix/presale/views/widget.py:682
|
||||
msgid "Event series"
|
||||
msgstr ""
|
||||
msgstr "Serie di eventi"
|
||||
|
||||
#: pretix/base/models/event.py:635 pretix/base/models/event.py:1508
|
||||
msgid "Seating plan"
|
||||
msgstr ""
|
||||
msgstr "Piani dei posti a sedere"
|
||||
|
||||
#: pretix/base/models/event.py:642 pretix/base/models/items.py:626
|
||||
#, fuzzy
|
||||
|
||||
@@ -19,21 +19,33 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from datetime import timedelta
|
||||
|
||||
from celery.result import AsyncResult
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.db.models import QuerySet
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.functional import lazy
|
||||
from rest_framework import serializers, viewsets
|
||||
from django.utils.timezone import now
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import serializers, status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
from pretix.api.serializers.i18n import I18nAwareModelSerializer
|
||||
from pretix.api.serializers.order import CompatibleJSONField
|
||||
|
||||
from ...api.serializers.fields import UploadedFileField
|
||||
from ...base.models import SalesChannel
|
||||
from ...base.models import CachedFile, OrderPosition, SalesChannel
|
||||
from ...base.pdf import PdfLayoutValidator
|
||||
from ...helpers.http import ChunkBasedFileResponse
|
||||
from ...multidomain.utils import static_absolute
|
||||
from .models import TicketLayout, TicketLayoutItem
|
||||
from .tasks import bulk_render
|
||||
|
||||
|
||||
class ItemAssignmentSerializer(I18nAwareModelSerializer):
|
||||
@@ -156,3 +168,123 @@ class TicketLayoutItemViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
**super().get_serializer_context(),
|
||||
'event': self.request.event,
|
||||
}
|
||||
|
||||
|
||||
with scopes_disabled():
|
||||
class RenderJobPartSerializer(serializers.Serializer):
|
||||
orderposition = serializers.PrimaryKeyRelatedField(
|
||||
queryset=OrderPosition.objects.none(),
|
||||
required=True,
|
||||
allow_null=False,
|
||||
)
|
||||
override_layout = serializers.PrimaryKeyRelatedField(
|
||||
queryset=TicketLayout.objects.none(),
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
override_channel = serializers.SlugRelatedField(
|
||||
queryset=SalesChannel.objects.none(),
|
||||
slug_field='identifier',
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class RenderJobSerializer(serializers.Serializer):
|
||||
parts = RenderJobPartSerializer(many=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['parts'].child.fields['orderposition'].queryset = OrderPosition.objects.filter(order__event=self.context['event'])
|
||||
self.fields['parts'].child.fields['override_layout'].queryset = self.context['event'].ticket_layouts.all()
|
||||
self.fields['parts'].child.fields['override_channel'].queryset = self.context['event'].organizer.sales_channels.all()
|
||||
|
||||
def validate(self, attrs):
|
||||
if len(attrs["parts"]) > 1000:
|
||||
raise ValidationError({"parts": ["Please do not submit more than 1000 parts."]})
|
||||
return super().validate(attrs)
|
||||
|
||||
|
||||
class TicketRendererViewSet(viewsets.ViewSet):
|
||||
permission = 'can_view_orders'
|
||||
|
||||
def get_serializer_kwargs(self):
|
||||
return {}
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
raise Http404()
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
raise Http404()
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
raise Http404()
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
raise Http404()
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
raise Http404()
|
||||
|
||||
@action(detail=False, methods=['GET'], url_name='download', url_path='download/(?P<asyncid>[^/]+)/(?P<cfid>[^/]+)')
|
||||
def download(self, *args, **kwargs):
|
||||
cf = get_object_or_404(CachedFile, id=kwargs['cfid'])
|
||||
if cf.file:
|
||||
resp = ChunkBasedFileResponse(cf.file.file, content_type=cf.type)
|
||||
resp['Content-Disposition'] = 'attachment; filename="{}"'.format(cf.filename).encode("ascii", "ignore")
|
||||
return resp
|
||||
elif not settings.HAS_CELERY:
|
||||
return Response(
|
||||
{'status': 'failed', 'message': 'Unknown file ID or export failed'},
|
||||
status=status.HTTP_410_GONE
|
||||
)
|
||||
|
||||
res = AsyncResult(kwargs['asyncid'])
|
||||
if res.failed():
|
||||
if isinstance(res.info, dict) and res.info['exc_type'] == 'ExportError':
|
||||
msg = res.info['exc_message']
|
||||
else:
|
||||
msg = 'Internal error'
|
||||
return Response(
|
||||
{'status': 'failed', 'message': msg},
|
||||
status=status.HTTP_410_GONE
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'status': 'running' if res.state in ('PROGRESS', 'STARTED', 'SUCCESS') else 'waiting',
|
||||
},
|
||||
status=status.HTTP_409_CONFLICT
|
||||
)
|
||||
|
||||
@action(detail=False, methods=['POST'])
|
||||
def render_batch(self, *args, **kwargs):
|
||||
serializer = RenderJobSerializer(data=self.request.data, context={
|
||||
"event": self.request.event,
|
||||
})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
cf = CachedFile(web_download=False)
|
||||
cf.date = now()
|
||||
cf.expires = now() + timedelta(hours=24)
|
||||
cf.save()
|
||||
async_result = bulk_render.apply_async(args=(
|
||||
self.request.event.id,
|
||||
str(cf.id),
|
||||
[
|
||||
{
|
||||
"orderposition": r["orderposition"].id,
|
||||
"override_layout": r["override_layout"].id if r.get("override_layout") else None,
|
||||
"override_channel": r["override_channel"].id if r.get("override_channel") else None,
|
||||
} for r in serializer.validated_data["parts"]
|
||||
]
|
||||
))
|
||||
|
||||
url_kwargs = {
|
||||
'asyncid': str(async_result.id),
|
||||
'cfid': str(cf.id),
|
||||
}
|
||||
url_kwargs.update(self.kwargs)
|
||||
return Response({
|
||||
'download': reverse('api-v1:ticketpdfrenderer-download', kwargs=url_kwargs, request=self.request)
|
||||
}, status=status.HTTP_202_ACCEPTED)
|
||||
|
||||
@@ -19,18 +19,26 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import json
|
||||
import logging
|
||||
from io import BytesIO
|
||||
|
||||
from django.core.files.base import ContentFile
|
||||
from django.db.models import Prefetch, prefetch_related_objects
|
||||
from pypdf import PdfWriter
|
||||
|
||||
from pretix.base.models import (
|
||||
CachedFile, Event, OrderPosition, cachedfile_name,
|
||||
CachedFile, Checkin, Event, EventMetaValue, ItemMetaValue,
|
||||
ItemVariationMetaValue, OrderPosition, SalesChannel, SubEventMetaValue,
|
||||
cachedfile_name,
|
||||
)
|
||||
from pretix.base.services.orders import OrderError
|
||||
from pretix.base.services.tasks import EventTask
|
||||
from pretix.celery_app import app
|
||||
|
||||
from ...base.i18n import language
|
||||
from ...base.services.export import ExportError
|
||||
from .models import TicketLayout
|
||||
from .ticketoutput import PdfTicketOutput
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -46,3 +54,93 @@ def tickets_create_pdf(event: Event, fileid: int, position: int, channel) -> int
|
||||
file.file.save(cachedfile_name(file, file.filename), ContentFile(data))
|
||||
file.save()
|
||||
return file.pk
|
||||
|
||||
|
||||
@app.task(base=EventTask, throws=(OrderError, ExportError,))
|
||||
def bulk_render(event: Event, fileid: int, parts: list) -> int:
|
||||
file = CachedFile.objects.get(id=fileid)
|
||||
|
||||
channels = SalesChannel.objects.in_bulk([p["override_channel"] for p in parts if p.get("override_channel")])
|
||||
layouts = TicketLayout.objects.in_bulk([p["override_layout"] for p in parts if p.get("override_layout")])
|
||||
|
||||
positions = OrderPosition.objects.all()
|
||||
prefetch_related_objects([event.organizer], 'meta_properties')
|
||||
prefetch_related_objects(
|
||||
[event],
|
||||
Prefetch('meta_values', queryset=EventMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached'),
|
||||
'questions',
|
||||
'item_meta_properties',
|
||||
)
|
||||
positions = positions.prefetch_related(
|
||||
Prefetch('checkins', queryset=Checkin.objects.select_related("device")),
|
||||
Prefetch('item', queryset=event.items.prefetch_related(
|
||||
Prefetch('meta_values', ItemMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached')
|
||||
)),
|
||||
'variation',
|
||||
'answers', 'answers__options', 'answers__question',
|
||||
'item__category',
|
||||
'addon_to__answers', 'addon_to__answers__options', 'addon_to__answers__question',
|
||||
Prefetch('addons', positions.select_related('item', 'variation')),
|
||||
Prefetch('subevent', queryset=event.subevents.prefetch_related(
|
||||
Prefetch('meta_values', to_attr='meta_values_cached',
|
||||
queryset=SubEventMetaValue.objects.select_related('property'))
|
||||
)),
|
||||
'linked_media',
|
||||
Prefetch('order', event.orders.select_related('invoice_address').prefetch_related(
|
||||
Prefetch(
|
||||
'positions',
|
||||
positions.prefetch_related(
|
||||
Prefetch('checkins', queryset=Checkin.objects.select_related('device')),
|
||||
Prefetch('item', queryset=event.items.prefetch_related(
|
||||
Prefetch('meta_values', ItemMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached')
|
||||
)),
|
||||
Prefetch('variation', queryset=event.items.prefetch_related(
|
||||
Prefetch('meta_values', ItemVariationMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached')
|
||||
)),
|
||||
'answers', 'answers__options', 'answers__question',
|
||||
'item__category',
|
||||
Prefetch('subevent', queryset=event.subevents.prefetch_related(
|
||||
Prefetch('meta_values', to_attr='meta_values_cached',
|
||||
queryset=SubEventMetaValue.objects.select_related('property'))
|
||||
)),
|
||||
Prefetch('addons', positions.select_related('item', 'variation', 'seat'))
|
||||
).select_related('addon_to', 'seat', 'addon_to__seat')
|
||||
)
|
||||
))
|
||||
).select_related(
|
||||
'addon_to', 'seat', 'addon_to__seat'
|
||||
)
|
||||
positions = positions.in_bulk([p["orderposition"] for p in parts])
|
||||
|
||||
merger = PdfWriter()
|
||||
for part in parts:
|
||||
p = positions[part["orderposition"]]
|
||||
p.order.event = event # performance optimization
|
||||
with (language(p.order.locale)):
|
||||
kwargs = {}
|
||||
if part.get("override_channel"):
|
||||
kwargs["override_channel"] = channels[part["override_channel"]].identifier
|
||||
if part.get("override_layout"):
|
||||
l = layouts[part["override_layout"]]
|
||||
kwargs["override_layout"] = json.loads(l.layout)
|
||||
kwargs["override_background"] = l.background
|
||||
prov = PdfTicketOutput(
|
||||
event,
|
||||
**kwargs,
|
||||
)
|
||||
filename, ctype, data = prov.generate(p)
|
||||
merger.append(ContentFile(data))
|
||||
|
||||
outbuffer = BytesIO()
|
||||
merger.write(outbuffer)
|
||||
merger.close()
|
||||
outbuffer.seek(0)
|
||||
|
||||
file.type = "application/pdf"
|
||||
file.file.save(cachedfile_name(file, file.filename), ContentFile(outbuffer.getvalue()))
|
||||
file.save()
|
||||
return file.pk
|
||||
|
||||
@@ -23,7 +23,7 @@ from django.urls import re_path
|
||||
|
||||
from pretix.api.urls import event_router
|
||||
from pretix.plugins.ticketoutputpdf.api import (
|
||||
TicketLayoutItemViewSet, TicketLayoutViewSet,
|
||||
TicketLayoutItemViewSet, TicketLayoutViewSet, TicketRendererViewSet,
|
||||
)
|
||||
from pretix.plugins.ticketoutputpdf.views import (
|
||||
LayoutCreate, LayoutDelete, LayoutEditorView, LayoutGetDefault,
|
||||
@@ -48,3 +48,4 @@ urlpatterns = [
|
||||
]
|
||||
event_router.register('ticketlayouts', TicketLayoutViewSet)
|
||||
event_router.register('ticketlayoutitems', TicketLayoutItemViewSet)
|
||||
event_router.register('ticketpdfrenderer', TicketRendererViewSet, basename='ticketpdfrenderer')
|
||||
|
||||
@@ -807,6 +807,19 @@ def test_event_update_plugins_validation(token_client, organizer, event, item, m
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"all_sales_channels": False,
|
||||
"limit_sales_channels": ["web"],
|
||||
"sales_channels": ["bar"],
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == ('{"limit_sales_channels":["If \'limit_sales_channels\' is set, the legacy '
|
||||
'attribute \'sales_channels\' must not be set or set to the same list."]}')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_event_test_mode(token_client, organizer, event):
|
||||
|
||||
@@ -782,3 +782,59 @@ def test_custom_rules_country_rate_subtract_from_gross(event):
|
||||
rate=Decimal('100.00'),
|
||||
name='',
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_no_negative_due_to_subtract_from_gross(event):
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("19.00"),
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('100.00'), subtract_from_gross=Decimal('200.00')).gross == Decimal("0.00")
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("0.00"),
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('100.00'), subtract_from_gross=Decimal('200.00')).gross == Decimal("0.00")
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("19.00"),
|
||||
price_includes_tax=False,
|
||||
)
|
||||
assert tr.tax(Decimal('100.00'), subtract_from_gross=Decimal('200.00')).gross == Decimal("0.00")
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("19.00"),
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('100.00'), subtract_from_gross=Decimal('200.00')).gross == Decimal("0.00")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_allow_negative(event):
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("19.00"),
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('-100.00')).gross == Decimal("-100.00")
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("0.00"),
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('-100.00')).gross == Decimal("-100.00")
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("19.00"),
|
||||
price_includes_tax=False,
|
||||
)
|
||||
assert tr.tax(Decimal('-100.00')).gross == Decimal("-119.00")
|
||||
tr = TaxRule(
|
||||
event=event,
|
||||
rate=Decimal("19.00"),
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('-100.00')).gross == Decimal("-100.00")
|
||||
|
||||
@@ -41,7 +41,7 @@ from django.contrib.auth.tokens import (
|
||||
PasswordResetTokenGenerator, default_token_generator,
|
||||
)
|
||||
from django.core import mail as djmail
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test import RequestFactory, TestCase, override_settings
|
||||
from django.utils.timezone import now
|
||||
from django_otp.oath import TOTP
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
@@ -50,6 +50,7 @@ from webauthn.authentication.verify_authentication_response import (
|
||||
)
|
||||
|
||||
from pretix.base.models import Organizer, Team, U2FDevice, User
|
||||
from pretix.control.views.auth import process_login
|
||||
from pretix.helpers import security
|
||||
|
||||
|
||||
@@ -892,6 +893,19 @@ class SessionTimeOutTest(TestCase):
|
||||
response = self.client.get('/control/')
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_plugin_auth_updates_auth_last_used(self):
|
||||
session = self.client.session
|
||||
session['pretix_auth_long_session'] = True
|
||||
session['pretix_auth_login_time'] = int(time.time()) - 3600 * 5
|
||||
session['pretix_auth_last_used'] = int(time.time()) - 3600 * 3 - 60
|
||||
session.save()
|
||||
|
||||
request = RequestFactory().get("/")
|
||||
request.session = self.client.session
|
||||
process_login(request, self.user, keep_logged_in=True)
|
||||
|
||||
assert request.session['pretix_auth_last_used'] >= int(time.time()) - 60
|
||||
|
||||
def test_update_session_activity(self):
|
||||
t1 = int(time.time()) - 5
|
||||
session = self.client.session
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#
|
||||
import copy
|
||||
import json
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
from django.core.files.base import ContentFile
|
||||
@@ -28,7 +30,9 @@ from django.utils.timezone import now
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from pretix.base.models import Event, Item, Organizer, Team
|
||||
from pretix.base.models import (
|
||||
Event, Item, Order, OrderPosition, Organizer, Team,
|
||||
)
|
||||
from pretix.plugins.ticketoutputpdf.models import TicketLayoutItem
|
||||
|
||||
|
||||
@@ -39,14 +43,35 @@ def env():
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
)
|
||||
t = Team.objects.create(organizer=event.organizer)
|
||||
t = Team.objects.create(organizer=event.organizer, can_view_orders=True)
|
||||
t.limit_events.add(event)
|
||||
item1 = Item.objects.create(event=event, name="Ticket", default_price=23)
|
||||
tl = event.ticket_layouts.create(name="Foo", default=True, layout='[{"a": 2}]')
|
||||
tl = event.ticket_layouts.create(
|
||||
name="Foo",
|
||||
default=True,
|
||||
layout='[{"type": "poweredby", "left": "0", "bottom": "0", "size": "1.00", "content": "dark"}]',
|
||||
)
|
||||
TicketLayoutItem.objects.create(layout=tl, item=item1, sales_channel=o.sales_channels.get(identifier="web"))
|
||||
return event, tl, item1
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def position(env):
|
||||
item = env[0].items.create(name="Ticket", default_price=3, admission=True)
|
||||
order = Order.objects.create(
|
||||
code='FOO', event=env[0], email='dummy@dummy.test',
|
||||
status=Order.STATUS_PAID, locale='en',
|
||||
datetime=now() - timedelta(days=4),
|
||||
expires=now() - timedelta(hours=4) + timedelta(days=10),
|
||||
total=Decimal('23.00'),
|
||||
sales_channel=env[0].organizer.sales_channels.get(identifier="web"),
|
||||
)
|
||||
return OrderPosition.objects.create(
|
||||
order=order, item=item, variation=None,
|
||||
price=Decimal("23.00"), attendee_name_parts={"full_name": "Peter"}, positionid=1
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
return APIClient()
|
||||
@@ -65,7 +90,7 @@ RES_LAYOUT = {
|
||||
'name': 'Foo',
|
||||
'default': True,
|
||||
'item_assignments': [{'item': 1, 'sales_channel': 'web'}],
|
||||
'layout': [{'a': 2}],
|
||||
'layout': [{"type": "poweredby", "left": "0", "bottom": "0", "size": "1.00", "content": "dark"}],
|
||||
'background': 'http://example.com/static/pretixpresale/pdf/ticket_default_a4.pdf'
|
||||
}
|
||||
|
||||
@@ -213,3 +238,92 @@ def test_api_delete(env, token_client):
|
||||
)
|
||||
assert resp.status_code == 204
|
||||
assert not env[0].ticket_layouts.exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_renderer_batch_valid(env, token_client, position):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"orderposition": position.pk,
|
||||
},
|
||||
{
|
||||
"orderposition": position.pk,
|
||||
"override_channel": "web",
|
||||
},
|
||||
{
|
||||
"orderposition": position.pk,
|
||||
"override_layout": env[1].pk,
|
||||
},
|
||||
]
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
assert resp.status_code == 202
|
||||
assert "download" in resp.data
|
||||
resp = token_client.get("/" + resp.data["download"].split("/", 3)[3])
|
||||
assert resp.status_code == 200
|
||||
assert resp["Content-Type"] == "application/pdf"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_renderer_batch_invalid(env, token_client, position):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"orderposition": -2,
|
||||
},
|
||||
]
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"parts": [{"orderposition": ["Invalid pk \"-2\" - object does not exist."]}]}
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"orderposition": position.pk,
|
||||
"override_layout": -2,
|
||||
},
|
||||
]
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"parts": [{"override_layout": ["Invalid pk \"-2\" - object does not exist."]}]}
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"orderposition": position.pk,
|
||||
"override_channel": "magic",
|
||||
},
|
||||
]
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"parts": [{"override_channel": ["Object with identifier=magic does not exist."]}]}
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"orderposition": position.pk,
|
||||
}
|
||||
] * 1002
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.data == {"parts": ["Please do not submit more than 1000 parts."]}
|
||||
|
||||
Reference in New Issue
Block a user