mirror of
https://github.com/pretix/pretix.git
synced 2026-06-11 01:25:13 +00:00
Fixes, cleanup, rebase
This commit is contained in:
@@ -99,6 +99,13 @@ class CheckinRPCRedeemInputSerializer(serializers.Serializer):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields['lists'].child_relation.queryset = CheckinList.objects.filter(event__in=self.context['events']).select_related('event')
|
self.fields['lists'].child_relation.queryset = CheckinList.objects.filter(event__in=self.context['events']).select_related('event')
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
exchange_fields = ["exchange_medium_type", "exchange_medium_identifier", "exchange_link_action"]
|
||||||
|
if any(attrs.get(k) is None for k in exchange_fields) and not all(attrs.get(k) is None for k in exchange_fields):
|
||||||
|
raise ValidationError("If you set any of exchange_medium_type, exchange_medium_identifier, or "
|
||||||
|
"exchange_link_action, you need to set all of them.")
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class MiniCheckinListSerializer(I18nAwareModelSerializer):
|
class MiniCheckinListSerializer(I18nAwareModelSerializer):
|
||||||
event = serializers.SlugRelatedField(slug_field='slug', read_only=True)
|
event = serializers.SlugRelatedField(slug_field='slug', read_only=True)
|
||||||
|
|||||||
@@ -466,7 +466,7 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
|||||||
|
|
||||||
device = auth if isinstance(auth, Device) else None
|
device = auth if isinstance(auth, Device) else None
|
||||||
gate = gate or (auth.gate if isinstance(auth, Device) else None)
|
gate = gate or (auth.gate if isinstance(auth, Device) else None)
|
||||||
media = None
|
medium = None
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'request': request,
|
'request': request,
|
||||||
@@ -805,15 +805,12 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
|||||||
locale = op.order.event.settings.locale
|
locale = op.order.event.settings.locale
|
||||||
with language(locale):
|
with language(locale):
|
||||||
try:
|
try:
|
||||||
exchange_requested = any(k is not None for k in [exchange_medium_type, exchange_medium_identifier, exchange_link_action])
|
if exchange_link_action and medium:
|
||||||
|
# Cannot scan a medium and then request to exchange it
|
||||||
if exchange_requested:
|
raise CheckInError(
|
||||||
if any(k is None for k in [exchange_medium_type, exchange_medium_identifier, exchange_link_action]):
|
gettext('You cannot exchange a medium for a medium.'),
|
||||||
raise ValidationError("If you set any of exchange_medium_type, exchange_medium_identifier, or "
|
'error'
|
||||||
"èxchange_link_action, you need to set all of them.")
|
)
|
||||||
if medium:
|
|
||||||
# Cannot scan a medium and then request to exchange it
|
|
||||||
raise ReusableMedium.DuplicateEntry()
|
|
||||||
|
|
||||||
checkin_args = dict(
|
checkin_args = dict(
|
||||||
op=op,
|
op=op,
|
||||||
@@ -836,7 +833,7 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
|||||||
reusable_medium=medium,
|
reusable_medium=medium,
|
||||||
)
|
)
|
||||||
|
|
||||||
if exchange_requested:
|
if exchange_link_action: # other fields are filled, see CheckinRPCRedeemInputSerializer.validate
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
# Do exchange and check-in atomically, i.e. both succeed or both fail
|
# Do exchange and check-in atomically, i.e. both succeed or both fail
|
||||||
medium = perform_media_exchange(
|
medium = perform_media_exchange(
|
||||||
@@ -848,11 +845,9 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
|||||||
user=user,
|
user=user,
|
||||||
auth=auth,
|
auth=auth,
|
||||||
)
|
)
|
||||||
source_type = media.media_type.identifier
|
source_type = medium.media_type.identifier
|
||||||
checkin_args['medium'] = medium
|
checkin_args['reusable_medium'] = medium
|
||||||
perform_checkin(
|
perform_checkin(**checkin_args)
|
||||||
reusable_media=media,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
perform_checkin(**checkin_args)
|
perform_checkin(**checkin_args)
|
||||||
except RequiredQuestionsError as e:
|
except RequiredQuestionsError as e:
|
||||||
@@ -877,26 +872,6 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
|||||||
'list': MiniCheckinListSerializer(list_by_event[op.order.event_id]).data,
|
'list': MiniCheckinListSerializer(list_by_event[op.order.event_id]).data,
|
||||||
'reason_explanation': e.msg,
|
'reason_explanation': e.msg,
|
||||||
}, status=400)
|
}, status=400)
|
||||||
except ReusableMedium.DoesNotExist:
|
|
||||||
return Response({
|
|
||||||
'status': 'error',
|
|
||||||
'reason': Checkin.REASON_MEDIUM_INVALID,
|
|
||||||
'reason_explanation': 'Reusable medium identifier not found',
|
|
||||||
'require_attention': op.require_checkin_attention,
|
|
||||||
'checkin_texts': op.checkin_texts,
|
|
||||||
'position': CheckinListOrderPositionSerializer(op, context=_make_context(context, op.order.event)).data,
|
|
||||||
'list': MiniCheckinListSerializer(list_by_event[op.order.event_id]).data,
|
|
||||||
}, status=400)
|
|
||||||
except ReusableMedium.DuplicateEntry:
|
|
||||||
return Response({
|
|
||||||
'status': 'error',
|
|
||||||
'reason': Checkin.REASON_MEDIUM_EXISTS,
|
|
||||||
'reason_explanation': 'Reusable medium identifier already exists',
|
|
||||||
'require_attention': op.require_checkin_attention,
|
|
||||||
'checkin_texts': op.checkin_texts,
|
|
||||||
'position': CheckinListOrderPositionSerializer(op, context=_make_context(context, op.order.event)).data,
|
|
||||||
'list': MiniCheckinListSerializer(list_by_event[op.order.event_id]).data,
|
|
||||||
}, status=400)
|
|
||||||
except CheckInError as e:
|
except CheckInError as e:
|
||||||
if not simulate:
|
if not simulate:
|
||||||
op.order.log_action('pretix.event.checkin.denied', data={
|
op.order.log_action('pretix.event.checkin.denied', data={
|
||||||
|
|||||||
@@ -138,9 +138,6 @@ class ReusableMedium(LoggedModel):
|
|||||||
]
|
]
|
||||||
ordering = "identifier", "type", "organizer"
|
ordering = "identifier", "type", "organizer"
|
||||||
|
|
||||||
class DuplicateEntry(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MediumKeySet(models.Model):
|
class MediumKeySet(models.Model):
|
||||||
organizer = models.ForeignKey('Organizer', on_delete=models.CASCADE, related_name='medium_key_sets')
|
organizer = models.ForeignKey('Organizer', on_delete=models.CASCADE, related_name='medium_key_sets')
|
||||||
|
|||||||
@@ -23,10 +23,13 @@ import secrets
|
|||||||
|
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
from pretix.base.models import GiftCardAcceptance, Item
|
from pretix.base.media import MEDIA_TYPES
|
||||||
|
from pretix.base.models import Checkin, GiftCardAcceptance, Item
|
||||||
from pretix.base.models.media import MediumKeySet, ReusableMedium
|
from pretix.base.models.media import MediumKeySet, ReusableMedium
|
||||||
|
from pretix.base.services.checkin import CheckInError
|
||||||
|
|
||||||
|
|
||||||
def create_nfc_mf0aes_keyset(organizer):
|
def create_nfc_mf0aes_keyset(organizer):
|
||||||
@@ -88,14 +91,47 @@ def perform_media_exchange(organizer, media_type, identifier, link_action, link_
|
|||||||
if link_action not in ('append', 'replace'):
|
if link_action not in ('append', 'replace'):
|
||||||
raise ValueError("Invalid link_action")
|
raise ValueError("Invalid link_action")
|
||||||
|
|
||||||
if media_policy == Item.MEDIA_POLICY_REUSE:
|
if media_type not in MEDIA_TYPES: # should be caught by serializer already
|
||||||
# Will and should raise ReusableMedium.DoesNotExist if not found
|
raise CheckInError(
|
||||||
medium = ReusableMedium.objects.get(
|
_('Invalid medium type.'),
|
||||||
type=media_type,
|
Checkin.REASON_ERROR,
|
||||||
identifier=identifier,
|
reason=_('Invalid medium type.'),
|
||||||
organizer=organizer,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not MEDIA_TYPES[media_type].is_active(organizer):
|
||||||
|
raise CheckInError(
|
||||||
|
_('Medium type is not enabled for organizer.'),
|
||||||
|
Checkin.REASON_ERROR,
|
||||||
|
reason=_('Medium type is not enabled for organizer.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
if link_orderposition.item.media_type != media_type:
|
||||||
|
raise CheckInError(
|
||||||
|
_('Incorrect medium type for product.'),
|
||||||
|
Checkin.REASON_PRODUCT,
|
||||||
|
reason=_('Incorrect medium type for product.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
if link_orderposition.linked_media.exists():
|
||||||
|
raise CheckInError(
|
||||||
|
_('Ticket is already exchanged for reusable medium.'),
|
||||||
|
Checkin.REASON_ALREADY_EXCHANGED,
|
||||||
|
reason=_('Ticket is already exchanged for reusable medium.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
if media_policy == Item.MEDIA_POLICY_REUSE:
|
||||||
|
try:
|
||||||
|
medium = ReusableMedium.objects.get(
|
||||||
|
type=media_type,
|
||||||
|
identifier=identifier,
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
except ReusableMedium.DoesNotExist:
|
||||||
|
raise CheckInError(
|
||||||
|
_('Reusable medium not found.'),
|
||||||
|
Checkin.REASON_MEDIUM_INVALID,
|
||||||
|
)
|
||||||
|
|
||||||
elif media_policy == Item.MEDIA_POLICY_REUSE_OR_NEW:
|
elif media_policy == Item.MEDIA_POLICY_REUSE_OR_NEW:
|
||||||
medium, created = ReusableMedium.objects.get_or_create(
|
medium, created = ReusableMedium.objects.get_or_create(
|
||||||
type=media_type,
|
type=media_type,
|
||||||
@@ -117,7 +153,10 @@ def perform_media_exchange(organizer, media_type, identifier, link_action, link_
|
|||||||
organizer=organizer,
|
organizer=organizer,
|
||||||
)
|
)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise ReusableMedium.DuplicateEntry()
|
raise CheckInError(
|
||||||
|
_('Reusable medium already exists.'),
|
||||||
|
Checkin.REASON_MEDIUM_EXISTS,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
medium.log_action(
|
medium.log_action(
|
||||||
'pretix.reusable_medium.created.auto',
|
'pretix.reusable_medium.created.auto',
|
||||||
@@ -125,6 +164,13 @@ def perform_media_exchange(organizer, media_type, identifier, link_action, link_
|
|||||||
auth=auth,
|
auth=auth,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise CheckInError(
|
||||||
|
_('Product does not support medium exchange.'),
|
||||||
|
Checkin.REASON_PRODUCT,
|
||||||
|
reason=_('Product does not support medium exchange.'),
|
||||||
|
)
|
||||||
|
|
||||||
if link_action == 'append':
|
if link_action == 'append':
|
||||||
medium.linked_orderpositions.add(link_orderposition)
|
medium.linked_orderpositions.add(link_orderposition)
|
||||||
elif link_action == 'replace':
|
elif link_action == 'replace':
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from tests.const import SAMPLE_PNG
|
|||||||
|
|
||||||
from pretix.api.serializers.item import QuestionSerializer
|
from pretix.api.serializers.item import QuestionSerializer
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Checkin, InvoiceAddress, Order, OrderPosition, ReusableMedium,
|
Checkin, InvoiceAddress, Item, Order, OrderPosition, ReusableMedium,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Lots of this code is overlapping with test_checkin.py, and some of it is arguably redundant since it's triggering
|
# Lots of this code is overlapping with test_checkin.py, and some of it is arguably redundant since it's triggering
|
||||||
@@ -1253,3 +1253,397 @@ def test_annul_failures(device_client, team, organizer, clist, clist_event2, eve
|
|||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
ci = p.all_checkins.get()
|
ci = p.all_checkins.get()
|
||||||
assert ci.successful
|
assert ci.successful
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_incomplete_body(token_client, organizer, clist, event, order):
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid"
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data == {
|
||||||
|
'non_field_errors': ['If you set any of exchange_medium_type, exchange_medium_identifier, or '
|
||||||
|
'exchange_link_action, you need to set all of them.']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_medium_for_medium(token_client, organizer, clist, event, order):
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="barcode",
|
||||||
|
identifier="abcdef",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.first())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "abcdef", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "barcode",
|
||||||
|
"exchange_medium_identifier": "hijkl",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'error'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_unknown_media_type(token_client, organizer, clist, event, order):
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "unknown",
|
||||||
|
"exchange_medium_identifier": "hijkl",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data == {"exchange_medium_type": ["\"unknown\" is not a valid choice."]}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_disabled_media_type(token_client, organizer, clist, event, order):
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "hijkl",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'error'
|
||||||
|
assert resp.data['reason_explanation'] == 'Medium type is not enabled for organizer.'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_mismatch_media_type(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "barcode"
|
||||||
|
item.save()
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'product'
|
||||||
|
assert resp.data['reason_explanation'] == 'Incorrect medium type for product.'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_no_item_policy(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.save()
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'product'
|
||||||
|
assert resp.data['reason_explanation'] == 'Product does not support medium exchange.'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_reuse_or_new_new(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.get(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
assert rm.linked_orderpositions.get().secret == "z3fsn8jyufm5kpk768q69gkbyr5f4h6w"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_reuse_or_new_reuse_replace(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_REUSE_OR_NEW
|
||||||
|
item.save()
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.last())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
rm.refresh_from_db()
|
||||||
|
with scopes_disabled():
|
||||||
|
assert rm.linked_orderpositions.get().secret == "z3fsn8jyufm5kpk768q69gkbyr5f4h6w"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_reuse_or_new_reuse_append(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_REUSE_OR_NEW
|
||||||
|
item.save()
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.last())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "append",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
rm.refresh_from_db()
|
||||||
|
with scopes_disabled():
|
||||||
|
assert rm.linked_orderpositions.count() == 2
|
||||||
|
assert rm.linked_orderpositions.filter(secret="z3fsn8jyufm5kpk768q69gkbyr5f4h6w").exists()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_reuse_exists_append(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_REUSE_OR_NEW
|
||||||
|
item.save()
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.last())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "append",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
rm.refresh_from_db()
|
||||||
|
with scopes_disabled():
|
||||||
|
assert rm.linked_orderpositions.count() == 2
|
||||||
|
assert rm.linked_orderpositions.filter(secret="z3fsn8jyufm5kpk768q69gkbyr5f4h6w").exists()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_reuse_not_exists(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_REUSE
|
||||||
|
item.save()
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'medium_invalid'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_new_exists(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.last())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "append",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'medium_exists'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_new_not_exists(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "12345678",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.get(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
assert rm.linked_orderpositions.get().secret == "z3fsn8jyufm5kpk768q69gkbyr5f4h6w"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchange_required(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'exchange'
|
||||||
|
assert resp.data['media_policy'] == 'new'
|
||||||
|
assert resp.data['media_type'] == 'nfc_uid'
|
||||||
|
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.first())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
# Force works
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"force": True,
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchanged_original_barcode_ok(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.first())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchanged_original_barcode_not_ok(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
organizer.settings.reusable_media_usage_enforced = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.first())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'already_exchanged'
|
||||||
|
# Force works
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"force": True,
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchanged_scan_medium_ok(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
organizer.settings.reusable_media_usage_enforced = True
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.first())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "12345678", {
|
||||||
|
"source_type": "nfc_uid",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.data['status'] == 'ok'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_exchanged_double_exchange(token_client, organizer, clist, event, order, item):
|
||||||
|
organizer.settings.reusable_media_type_nfc_uid = True
|
||||||
|
organizer.settings.reusable_media_usage_enforced = False
|
||||||
|
item.media_type = "nfc_uid"
|
||||||
|
item.media_policy = Item.MEDIA_POLICY_NEW
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
with scopes_disabled():
|
||||||
|
rm = ReusableMedium.objects.create(
|
||||||
|
type="nfc_uid",
|
||||||
|
identifier="12345678",
|
||||||
|
organizer=organizer,
|
||||||
|
)
|
||||||
|
rm.linked_orderpositions.add(order.positions.first())
|
||||||
|
resp = _redeem(token_client, organizer, clist, "z3fsn8jyufm5kpk768q69gkbyr5f4h6w", {
|
||||||
|
"source_type": "barcode",
|
||||||
|
"exchange_medium_type": "nfc_uid",
|
||||||
|
"exchange_medium_identifier": "87654321",
|
||||||
|
"exchange_link_action": "replace",
|
||||||
|
})
|
||||||
|
assert resp.status_code == 400
|
||||||
|
assert resp.data['status'] == 'error'
|
||||||
|
assert resp.data['reason'] == 'already_exchanged'
|
||||||
|
|||||||
Reference in New Issue
Block a user