diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index 1d89ac694a..9460c90673 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -117,7 +117,8 @@ cancellation_date datetime Time of order c reliable for orders that have been cancelled, reactivated and cancelled again. plugin_data object Additional data added by plugins. -use_gift_cards list of strings List of gift card secrets that are used to pay for this order. +use_gift_cards list of strings List of unique gift card secrets that are used to pay + for this order. ===================================== ========================== ======================================================= diff --git a/src/pretix/api/serializers/order.py b/src/pretix/api/serializers/order.py index 8d1788435f..249a44bd0f 100644 --- a/src/pretix/api/serializers/order.py +++ b/src/pretix/api/serializers/order.py @@ -1316,6 +1316,8 @@ class OrderCreateSerializer(I18nAwareModelSerializer): if validated_data.get('status') != Order.STATUS_PENDING and len(gift_card_secrets) > 0: raise ValidationError({"use_gift_cards": ['The attribute use_gift_cards is only supported for orders that are created as pending']}) + if len(set(gift_card_secrets)) != len(gift_card_secrets): + raise ValidationError({"use_gift_cards": ['Multiple copies of the same gift card secret are not allowed']}) if not validated_data.get("sales_channel"): validated_data["sales_channel"] = self.context['event'].organizer.sales_channels.get(identifier="web") diff --git a/src/tests/api/test_order_create.py b/src/tests/api/test_order_create.py index caa2528790..242894839f 100644 --- a/src/tests/api/test_order_create.py +++ b/src/tests/api/test_order_create.py @@ -3551,3 +3551,33 @@ def test_order_create_use_gift_card_and_payment_provider(token_client, organizer assert open_payment.state == OrderPayment.PAYMENT_STATE_CREATED assert open_payment.amount == o.total - gc_value assert open_payment.payment_provider.identifier == res['payment_provider'] + + +@pytest.mark.django_db +def test_order_create_use_gift_card_repeated(token_client, organizer, event, item, quota, question): + res = copy.deepcopy(ORDER_CREATE_PAYLOAD) + res['positions'][0]['item'] = item.pk + res['positions'][0]['answers'][0]['question'] = question.pk + with scopes_disabled(): + customer = organizer.customers.create() + res['customer'] = customer.identifier + res['api_meta'] = { + 'test': 1 + } + del res['payment_provider'] + + gc_one_eur = GiftCard.objects.create(issuer=organizer, currency='EUR') + gc_one_eur.transactions.create(value=Decimal("1.00"), acceptor=organizer).save() + + gc_enough_eur = GiftCard.objects.create(issuer=organizer, currency='EUR') + gc_enough_eur.transactions.create(value=Decimal("100.00"), acceptor=organizer).save() + + res['use_gift_cards'] = [gc_one_eur.secret, gc_one_eur.secret, gc_enough_eur.secret] + + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/orders/'.format( + organizer.slug, event.slug + ), format='json', data=res + ) + assert resp.status_code == 400 + assert resp.json() == {'use_gift_cards': ['Multiple copies of the same gift card secret are not allowed']}