Compare commits

..

17 Commits

Author SHA1 Message Date
Raphael Michel
50f44b4d4d Silence ResponseError from redis 2022-06-05 20:41:03 +02:00
Raphael Michel
d4825d00fb Fix copying variations when copying items 2022-05-20 16:09:57 +02:00
Raphael Michel
591f5a75ef Fix error handling on add-ons selection step (#2659)
Co-authored-by: Richard Schreiber <wiffbi@gmail.com>
2022-05-19 13:27:28 +02:00
Dennis Lichtenthäler
15407732ea Translations: Update German
Currently translated at 100.0% (4732 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2022-05-19 09:58:18 +02:00
Ola Ola
82534f49da Translations: Update Ukrainian
Currently translated at 76.3% (3615 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/uk/

powered by weblate
2022-05-19 09:58:18 +02:00
Raphael Michel
6c7f76fe96 Orders API: Allow downloading tickets for pending orders (#2657)
Co-authored-by: Richard Schreiber <wiffbi@gmail.com>
2022-05-19 09:58:06 +02:00
Raphael Michel
08590f9d98 Explicitly store whether checkins were offline (#2617) 2022-05-17 14:32:14 +02:00
Raphael Michel
074252a9c0 SecretKeySettingsWidget: Fix issue during form validation 2022-05-17 13:56:38 +02:00
Raphael Michel
615f7ed2cf Translations: Update Ukrainian
Currently translated at 76.3% (3612 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/uk/

powered by weblate
2022-05-13 17:13:05 +02:00
Iryna Loik
e3a4435356 Translations: Update Ukrainian
Currently translated at 76.3% (3612 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/uk/

powered by weblate
2022-05-13 17:13:05 +02:00
Jonathan Berger
e8ec2a8d1f Translations: Update French
Currently translated at 47.6% (2254 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2022-05-13 17:13:05 +02:00
hmontheline
17cac62c31 Translations: Update French
Currently translated at 47.6% (2254 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2022-05-13 17:13:05 +02:00
Jonathan Berger
73beabedea Translations: Update French
Currently translated at 47.4% (2244 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/fr/

powered by weblate
2022-05-13 17:13:05 +02:00
Iryna Loik
93f0e818e4 Translations: Update Ukrainian
Currently translated at 69.9% (3309 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/uk/

powered by weblate
2022-05-13 17:13:05 +02:00
Iryna N
54ff5967fc Translations: Update Ukrainian
Currently translated at 69.9% (3309 of 4732 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/uk/

powered by weblate
2022-05-13 17:13:05 +02:00
Richard Schreiber
41b18b9419 Make customer identifier unique per organizer (#2647) 2022-05-13 16:40:34 +02:00
Raphael Michel
750a2511d5 Fix incorrect escaping of QR code secrets 2022-05-13 16:36:48 +02:00
18 changed files with 673 additions and 433 deletions

View File

@@ -609,13 +609,17 @@ Fetching individual orders
Order ticket download
---------------------
.. versionchanged:: 4.10
The API now supports ticket downloads for pending orders if allowed by the event settings.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/download/(output)/
Download tickets for an order, identified by its order code. Depending on the chosen output, the response might
be a ZIP file, PDF file or something else. The order details response contains a list of output options for this
particular order.
Tickets can be only downloaded if the order is paid and if ticket downloads are active. Note that in some cases the
Tickets can only be downloaded if ticket downloads are active and depending on event settings the order is either paid or pending. Note that in some cases the
ticket file might not yet have been created. In that case, you will receive a status code :http:statuscode:`409` and
you are expected to retry the request after a short period of waiting.
@@ -1635,6 +1639,10 @@ Fetching individual positions
Order position ticket download
------------------------------
.. versionchanged:: 4.10
The API now supports ticket downloads for pending orders if allowed by the event settings.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orderpositions/(id)/download/(output)/
Download tickets for one order position, identified by its internal ID.
@@ -1646,7 +1654,7 @@ Order position ticket download
The referenced URL can provide a download or a regular, human-viewable website - so it is advised to open this URL
in a webbrowser and leave it up to the user to handle the result.
Tickets can be only downloaded if the order is paid and if ticket downloads are active. Also, depending on event
Tickets can only be downloaded if ticket downloads are active and depending on event settings the order is either paid or pending. Also, depending on event
configuration downloads might be only unavailable for add-on products or non-admission products.
Note that in some cases the ticket file might not yet have been created. In that case, you will receive a status
code :http:statuscode:`409` and you are expected to retry the request after a short period of waiting.

View File

@@ -157,6 +157,7 @@ class CheckinListViewSet(viewsets.ModelViewSet):
list=self.get_object(),
successful=False,
forced=True,
force_sent=True,
device=self.request.auth if isinstance(self.request.auth, Device) else None,
gate=self.request.auth.gate if isinstance(self.request.auth, Device) else None,
**kwargs,

View File

@@ -261,8 +261,11 @@ class OrderViewSet(viewsets.ModelViewSet):
provider = self._get_output_provider(output)
order = self.get_object()
if order.status != Order.STATUS_PAID:
raise PermissionDenied("Downloads are not available for unpaid orders.")
if order.status in (Order.STATUS_CANCELED, Order.STATUS_EXPIRED):
raise PermissionDenied("Downloads are not available for canceled or expired orders.")
if order.status == Order.STATUS_PENDING and not request.event.settings.ticket_download_pending:
raise PermissionDenied("Downloads are not available for pending orders.")
ct = CachedCombinedTicket.objects.filter(
order=order, provider=provider.identifier, file__isnull=False
@@ -1119,8 +1122,11 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
provider = self._get_output_provider(output)
pos = self.get_object()
if pos.order.status != Order.STATUS_PAID:
raise PermissionDenied("Downloads are not available for unpaid orders.")
if pos.order.status in (Order.STATUS_CANCELED, Order.STATUS_EXPIRED):
raise PermissionDenied("Downloads are not available for canceled or expired orders.")
if pos.order.status == Order.STATUS_PENDING and not request.event.settings.ticket_download_pending:
raise PermissionDenied("Downloads are not available for pending orders.")
if not pos.generate_ticket:
raise PermissionDenied("Downloads are not enabled for this product.")

View File

@@ -196,10 +196,16 @@ class SecretKeySettingsWidget(forms.TextInput):
attrs.update({
'autocomplete': 'new-password' # see https://bugs.chromium.org/p/chromium/issues/detail?id=370363#c7
})
self.__reflect_value = False
super().__init__(attrs)
def value_from_datadict(self, data, files, name):
value = super().value_from_datadict(data, files, name)
self.__reflect_value = value and value != SECRET_REDACTED
return value
def get_context(self, name, value, attrs):
if value:
if value and not self.__reflect_value:
value = SECRET_REDACTED
return super().get_context(name, value, attrs)

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2022-04-29 13:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0215_customer_organizer_identifier_unique'),
]
operations = [
migrations.AddField(
model_name='checkin',
name='force_sent',
field=models.BooleanField(default=False, null=True),
),
]

View File

@@ -326,7 +326,13 @@ class Checkin(models.Model):
type = models.CharField(max_length=100, choices=CHECKIN_TYPES, default=TYPE_ENTRY)
nonce = models.CharField(max_length=190, null=True, blank=True)
# Whether or not the scan was made offline
force_sent = models.BooleanField(default=False, null=True, blank=True)
# Whether the scan was made offline AND would have not been possible online
forced = models.BooleanField(default=False)
device = models.ForeignKey(
'pretixbase.Device', related_name='checkins', on_delete=models.PROTECT, null=True, blank=True
)

View File

@@ -796,6 +796,7 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
gate=device.gate if device else None,
nonce=nonce,
forced=force and (not entry_allowed or from_revoked_secret),
force_sent=force,
raw_barcode=raw_barcode,
)
op.order.log_action('pretix.event.checkin', data={

View File

@@ -36,6 +36,7 @@ from django.utils import timezone, translation
from django.utils.timezone import get_current_timezone
from django.utils.translation import get_language, gettext as _
from django.views.generic import FormView
from redis import ResponseError
from pretix.base.models import User
from pretix.base.services.tasks import ProfiledEventTask
@@ -68,6 +69,11 @@ class AsyncMixin:
res.get(timeout=timeout, propagate=False)
except celery.exceptions.TimeoutError:
pass
except ResponseError:
# There is a long-standing concurrency issue in either celery or redis-py that hasn't been fixed
# yet. Instead of crashing, we can ignore it and the client will retry their request and hopefully
# it is fixed next time.
logger.warning('Ignored ResponseError in AsyncResult.get()')
except ConnectionError:
# Redis probably just restarted, let's just report not ready and retry next time
data = self._ajax_response_data()

View File

@@ -32,6 +32,7 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
import copy
import os
from decimal import Decimal
from urllib.parse import urlencode
@@ -423,9 +424,10 @@ class ItemCreateForm(I18nModelForm):
if self.cleaned_data.get('has_variations'):
if self.cleaned_data.get('copy_from') and self.cleaned_data.get('copy_from').has_variations:
for variation in self.cleaned_data['copy_from'].variations.all():
ItemVariation.objects.create(item=instance, value=variation.value, active=variation.active,
position=variation.position, default_price=variation.default_price,
description=variation.description, original_price=variation.original_price)
v = copy.copy(variation)
v.pk = None
v.item = instance
v.save()
else:
ItemVariation.objects.create(
item=instance, value=__('Standard')

View File

@@ -80,13 +80,17 @@
{% elif c.forced and c.successful %}
<span class="fa fa-fw fa-warning" data-toggle="tooltip"
title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Additional entry scan: {{ date }}{% endblocktrans %}"></span>
{% elif c.forced and not c.successful %}
<br>
<small class="text-muted">{% trans "Failed in offline mode" %}</small>
{% elif c.force_sent %}
<span class="fa fa-fw fa-cloud-upload" data-toggle="tooltip"
title="{% blocktrans trimmed with date=c.created|date:'SHORT_DATETIME_FORMAT' %}Offline scan. Upload time: {{ date }}{% endblocktrans %}"></span>
{% elif c.auto_checked_in %}
<span class="fa fa-fw fa-magic" data-toggle="tooltip"
title="{% blocktrans trimmed with date=c.datetime|date:'SHORT_DATETIME_FORMAT' %}Automatically checked in: {{ date }}{% endblocktrans %}"></span>
{% endif %}
{% if c.forced and not c.successful %}
<br>
<small class="text-muted">{% trans "Failed in offline mode" %}</small>
{% endif %}
</td>
<td>
{% if c.type == "exit" %}<span class="fa fa-fw fa-sign-out"></span>{% endif %}

View File

@@ -5,8 +5,8 @@ msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-28 16:44+0000\n"
"PO-Revision-Date: 2022-04-28 18:04+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"PO-Revision-Date: 2022-05-16 19:00+0000\n"
"Last-Translator: Dennis Lichtenthäler <lichtenthaeler@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/"
">\n"
"Language: de\n"
@@ -24436,7 +24436,7 @@ msgid ""
"methods such as giropay, iDEAL, Alipay,and many more."
msgstr ""
"Akzeptieren Sie Zahlungen über Stripe, einen weltweit beliebten "
"Zahlungsdienstleister. PayPal unterstützt Zahlungen per Kreditkarte sowie "
"Zahlungsdienstleister. Stripe unterstützt Zahlungen per Kreditkarte sowie "
"viele lokale Zahlungsarten wie z.B. giropay, iDEAL, Alipay, und viele mehr."
#: pretix/plugins/stripe/forms.py:40

View File

@@ -4,8 +4,8 @@ msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-28 16:44+0000\n"
"PO-Revision-Date: 2022-05-09 15:43+0000\n"
"Last-Translator: hmontheline <Helias.mackay@goetheanum.ch>\n"
"PO-Revision-Date: 2022-05-13 14:36+0000\n"
"Last-Translator: Jonathan Berger <drskullster@gmail.com>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
">\n"
"Language: fr\n"
@@ -1291,10 +1291,8 @@ msgstr "Date de commande"
#: pretix/base/exporters/orderlist.py:444
#: pretix/base/exporters/orderlist.py:547
#: pretix/plugins/checkinlists/exporters.py:469
#, fuzzy
#| msgid "Order date"
msgid "Order time"
msgstr "Date de commande"
msgstr "Heure de commande"
#: pretix/base/exporters/orderlist.py:280
#, fuzzy
@@ -1542,60 +1540,44 @@ msgstr "Tickets"
#: pretix/base/exporters/orderlist.py:577 pretix/base/orderimport.py:671
#: pretix/plugins/checkinlists/exporters.py:472
#, fuzzy
#| msgid "Client ID"
msgid "Seat ID"
msgstr "Numéro de client"
msgstr "Numéro de siège"
#: pretix/base/exporters/orderlist.py:578
#: pretix/plugins/checkinlists/exporters.py:473
#, fuzzy
#| msgid "Team name"
msgid "Seat name"
msgstr "Nom de l'équipe"
msgstr "Nom du siège"
#: pretix/base/exporters/orderlist.py:579
#: pretix/plugins/checkinlists/exporters.py:474
#, fuzzy
#| msgid "Team name"
msgid "Seat zone"
msgstr "Nom de l'équipe"
msgstr "Zone du siège"
#: pretix/base/exporters/orderlist.py:580
#: pretix/plugins/checkinlists/exporters.py:475
#, fuzzy
#| msgid "Client ID"
msgid "Seat row"
msgstr "Numéro de client"
msgstr "Rangée du siège"
#: pretix/base/exporters/orderlist.py:581
#: pretix/plugins/checkinlists/exporters.py:476
#, fuzzy
#| msgid "Team name"
msgid "Seat number"
msgstr "Nom de l'équipe"
msgstr "Numéro de siège"
#: pretix/base/exporters/orderlist.py:582
#, fuzzy
#| msgid "Order code"
msgid "Order comment"
msgstr "Code de commande"
msgstr "Commentaire de commande"
#: pretix/base/exporters/orderlist.py:750
msgid "Order payments and refunds"
msgstr "Commandes et remboursements"
#: pretix/base/exporters/orderlist.py:758
#, fuzzy
#| msgid "Payment date"
msgid "Payment states"
msgstr "Date de paiement"
msgstr "États de paiement"
#: pretix/base/exporters/orderlist.py:766
#, fuzzy
#| msgid "Check-in status"
msgid "Refund states"
msgstr "Statut d'enregistrement"
msgstr "Etats des remboursements"
#: pretix/base/exporters/orderlist.py:791
#: pretix/base/exporters/orderlist.py:930
@@ -1802,10 +1784,8 @@ msgstr "Remises par cartes-cadeaux"
#: pretix/base/exporters/orderlist.py:969
#: pretix/control/templates/pretixcontrol/giftcards/payment.html:10
#, fuzzy
#| msgid "Voucher details"
msgid "Issuer"
msgstr "Détails du bon"
msgstr "Emetteur"
#: pretix/base/exporters/orderlist.py:997 pretix/control/navigation.py:523
#: pretix/control/templates/pretixcontrol/organizers/edit.html:84
@@ -2039,10 +2019,8 @@ msgid "Please do not use special characters in names."
msgstr "Veuillez entrer votre nom."
#: pretix/base/forms/questions.py:257
#, fuzzy
#| msgid "Please enter your name."
msgid "Please enter a shorter name."
msgstr "Veuillez entrer votre nom."
msgstr "Veuillez entrer un nom plus court."
#: pretix/base/forms/questions.py:274
#, fuzzy

File diff suppressed because it is too large Load Diff

View File

@@ -618,6 +618,7 @@ class CheckinLogList(ListExporter):
_('Product'),
_('Name'),
_('Device'),
_('Offline'),
_('Offline override'),
_('Automatically checked in'),
_('Gate'),
@@ -664,6 +665,7 @@ class CheckinLogList(ListExporter):
str(ci.position.item) if ci.position else (str(ci.raw_item) if ci.raw_item else ''),
(ci.position.attendee_name or ia.name) if ci.position else '',
str(ci.device) if ci.device else '',
_('Yes') if ci.force_sent is True else (_('No') if ci.force_sent is False else '?'),
_('Yes') if ci.forced else _('No'),
_('Yes') if ci.auto_checked_in else _('No'),
str(ci.gate or ''),

View File

@@ -70,6 +70,7 @@ function async_task_check_error(jqXHR, textStatus, errorThrown) {
jqXHR.responseText.indexOf("<body"),
jqXHR.responseText.indexOf("</body")
));
setup_basics($("body"));
form_handlers($("body"));
setup_collapsible_details($("body"));
window.setTimeout(function () { $(window).scrollTop(0) }, 200)
@@ -152,6 +153,7 @@ function async_task_error(jqXHR, textStatus, errorThrown) {
if (respdom.filter('#page-wrapper') && $('#page-wrapper').length) {
$("#page-wrapper").html(respdom.find("#page-wrapper").html());
setup_basics($("#page-wrapper"));
form_handlers($("#page-wrapper"));
setup_collapsible_details($("#page-wrapper"));
$(document).trigger("pretix:bind-forms");
@@ -161,6 +163,7 @@ function async_task_error(jqXHR, textStatus, errorThrown) {
jqXHR.responseText.indexOf("<body"),
jqXHR.responseText.indexOf("</body")
));
setup_basics($("body"));
form_handlers($("body"));
setup_collapsible_details($("body"));
$(document).trigger("pretix:bind-forms");

View File

@@ -918,7 +918,7 @@ $(function () {
height: 196
}
);
$div.append($(this).attr("data-qrcode").slice(0, 10) + "…<br>");
$div.append($("<div>").text($(this).attr("data-qrcode").slice(0, 10)).get(0).innerHTML + "…<br>");
$div.append(gettext("Click to close"));
$div.slideDown(200);
$div.click(function (e) {

View File

@@ -174,6 +174,63 @@ var form_handlers = function (el) {
}
};
function setup_basics(el) {
el.find("input[data-toggle=radiocollapse]").change(function () {
$($(this).attr("data-parent")).find(".collapse.in").collapse('hide');
$($(this).attr("data-target")).collapse('show');
});
el.find(".js-only").removeClass("js-only");
el.find(".js-hidden").hide();
el.find("div.collapsed").removeClass("collapsed").addClass("collapse");
el.find(".has-error, .alert-danger").each(function () {
$(this).closest("div.panel-collapse").collapse("show");
});
el.find(".has-error").first().each(function(){
if ($(this).is(':input')) this.focus();
else $(":input", this).get(0).focus();
});
el.find(".alert-danger").first().each(function() {
var content = $("<ul></ul>").click(function(e) {
var input = $(e.target.hash).get(0);
if (input) input.focus();
input.scrollIntoView({block: "center"});
e.preventDefault();
});
$(".has-error").each(function() {
var target = target = $(":input", this);
var desc = $("#" + target.attr("aria-describedby").split(' ', 1)[0]);
// multi-input fields have a role=group with aria-labelledby
var label = this.hasAttribute("aria-labelledby") ? $("#" + this.getAttribute("aria-labelledby")) : $("[for="+target.attr("id")+"]");
var $li = $("<li>");
$li.text(": " + desc.text())
$li.prepend($("<a>").attr("href", "#" + target.attr("id")).text(label.get(0).childNodes[0].nodeValue))
content.append($li);
});
$(this).append(content);
});
el.find("[data-click-to-load]").on("click", function(e) {
var target = document.getElementById(this.getAttribute("data-click-to-load"));
target.src = this.href;
target.focus();
e.preventDefault();
});
el.find('[data-toggle="tooltip"]').tooltip();
// AddOns
el.find('.addon-variation-description').hide();
el.find('.toggle-variation-description').click(function () {
$(this).parent().find('.addon-variation-description').slideToggle();
});
el.find('input[type=radio][description]').change(function () {
if ($(this).prop("checked")) {
$(this).parent().parent().find('.addon-variation-description').stop().slideDown();
}
});
}
$(function () {
"use strict";
@@ -191,48 +248,7 @@ $(function () {
if (!$input.prop("checked")) $input.prop('checked', true).trigger("change");
});
$("input[data-toggle=radiocollapse]").change(function () {
$($(this).attr("data-parent")).find(".collapse.in").collapse('hide');
$($(this).attr("data-target")).collapse('show');
});
$(".js-only").removeClass("js-only");
$(".js-hidden").hide();
$("div.collapsed").removeClass("collapsed").addClass("collapse");
$(".has-error, .alert-danger").each(function () {
$(this).closest("div.panel-collapse").collapse("show");
});
$(".has-error").first().each(function(){
if ($(this).is(':input')) this.focus();
else $(":input", this).get(0).focus();
});
$(".alert-danger").first().each(function() {
var content = $("<ul></ul>").click(function(e) {
var input = $(e.target.hash).get(0);
if (input) input.focus();
input.scrollIntoView({block: "center"});
e.preventDefault();
});
$(".has-error").each(function() {
var target = target = $(":input", this);
var desc = $("#" + target.attr("aria-describedby").split(' ', 1)[0]);
// multi-input fields have a role=group with aria-labelledby
var label = this.hasAttribute("aria-labelledby") ? $("#" + this.getAttribute("aria-labelledby")) : $("[for="+target.attr("id")+"]");
var $li = $("<li>");
$li.text(": " + desc.text())
$li.prepend($("<a>").attr("href", "#" + target.attr("id")).text(label.get(0).childNodes[0].nodeValue))
content.append($li);
});
$(this).append(content);
});
$("[data-click-to-load]").on("click", function(e) {
var target = document.getElementById(this.getAttribute("data-click-to-load"));
target.src = this.href;
target.focus();
e.preventDefault();
});
setup_basics($("body"));
$(".overlay-remove").on("click", function() {
$(this).closest(".contains-overlay").find(".overlay").fadeOut();
});
@@ -244,21 +260,8 @@ $(function () {
$("#voucher-toggle").slideUp();
});
$('[data-toggle="tooltip"]').tooltip();
$("#ajaxerr").on("click", ".ajaxerr-close", ajaxErrDialog.hide);
// AddOns
$('.addon-variation-description').hide();
$('.toggle-variation-description').click(function () {
$(this).parent().find('.addon-variation-description').slideToggle();
});
$('input[type=radio][description]').change(function () {
if ($(this).prop("checked")) {
$(this).parent().parent().find('.addon-variation-description').stop().slideDown();
}
});
// Copy answers
$(".js-copy-answers").click(function (e) {
e.preventDefault();

View File

@@ -814,6 +814,7 @@ def test_forced_flag_set_if_required(token_client, organizer, clist, event, orde
), {'force': True}, format='json')
with scopes_disabled():
assert not p.checkins.order_by('pk').last().forced
assert p.checkins.order_by('pk').last().force_sent
assert resp.status_code == 201
assert resp.data['status'] == 'ok'
resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format(
@@ -821,6 +822,7 @@ def test_forced_flag_set_if_required(token_client, organizer, clist, event, orde
), {'force': True}, format='json')
with scopes_disabled():
assert p.checkins.order_by('pk').last().forced
assert p.checkins.order_by('pk').last().force_sent
assert resp.status_code == 201
assert resp.data['status'] == 'ok'
@@ -1184,6 +1186,7 @@ def test_redeem_unknown_revoked_force(token_client, organizer, clist, event, ord
assert resp.data["status"] == "ok"
with scopes_disabled():
assert Checkin.objects.last().forced
assert Checkin.objects.last().force_sent
@pytest.mark.django_db