make payment_provider and use_gift_cards exclusive

This commit is contained in:
Lukas Bockstaller
2026-03-10 17:25:47 +01:00
parent 353a08e094
commit a21e67a9ba
3 changed files with 22 additions and 18 deletions

View File

@@ -1104,10 +1104,9 @@ Creating orders
pay for the order. Processing of the gift cards stops as soon as the order is payed for. All gift card transactions pay for the order. Processing of the gift cards stops as soon as the order is payed for. All gift card transactions
are listed under ``payments`` in the response. are listed under ``payments`` in the response.
This option can only be used with orders that are in the pending state. This option can only be used with orders that are in the pending state.
In addition to ``use_gift_cards``, you can provide ``payment_info`` and ``payment_provider`` fields. A matching The ``use_gift_cards`` attribute can not be combined with ``payment_info`` and ``payment_provider`` fields. If the
payment record for the ``payment_provider`` will be created once all the gift cards have been processed. This order isn't completely paid after its creation with ``use_gift_cards``, then a subsequent request to the payment
entry's amount is what you'll need to charge your customer. The above-mentioned caveats for ``payment_info`` still endpoint is needed.
apply.
If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually
to incrementing integers starting with ``1``. Then, you can reference one of these to incrementing integers starting with ``1``. Then, you can reference one of these

View File

@@ -1314,6 +1314,8 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
simulate = validated_data.pop('simulate', False) simulate = validated_data.pop('simulate', False)
gift_card_secrets = validated_data.pop('use_gift_cards') if 'use_gift_cards' in validated_data else [] gift_card_secrets = validated_data.pop('use_gift_cards') if 'use_gift_cards' in validated_data else []
if (payment_provider is not None or payment_info != '{}') and len(gift_card_secrets) > 0:
raise ValidationError({"use_gift_cards": ['The attribute use_gift_cards is not compatible with payment_provider or payment_info']})
if validated_data.get('status') != Order.STATUS_PENDING and len(gift_card_secrets) > 0: 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']}) 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): if len(set(gift_card_secrets)) != len(gift_card_secrets):

View File

@@ -3400,6 +3400,7 @@ def test_order_create_use_gift_cards_only_pending(token_client, organizer, event
gc.transactions.create(value=Decimal("100.00"), acceptor=organizer).save() gc.transactions.create(value=Decimal("100.00"), acceptor=organizer).save()
res['status'] = order_status res['status'] = order_status
del res['payment_provider']
res['use_gift_cards'] = [gc.secret] res['use_gift_cards'] = [gc.secret]
resp = token_client.post( resp = token_client.post(
@@ -3430,7 +3431,6 @@ def test_order_create_use_gift_card(token_client, organizer, event, item, quota,
res['positions'][0]['answers'][0]['question'] = question.pk res['positions'][0]['answers'][0]['question'] = question.pk
with scopes_disabled(): with scopes_disabled():
customer = organizer.customers.create() customer = organizer.customers.create()
del res['payment_provider']
res['customer'] = customer.identifier res['customer'] = customer.identifier
res['api_meta'] = { res['api_meta'] = {
@@ -3442,7 +3442,7 @@ def test_order_create_use_gift_card(token_client, organizer, event, item, quota,
gc = GiftCard.objects.create(issuer=organizer, currency='EUR') gc = GiftCard.objects.create(issuer=organizer, currency='EUR')
gc.transactions.create(value=Decimal("100.00"), acceptor=organizer).save() gc.transactions.create(value=Decimal("100.00"), acceptor=organizer).save()
del res['payment_provider']
res['use_gift_cards'] = [gc.secret] res['use_gift_cards'] = [gc.secret]
djmail.outbox = [] djmail.outbox = []
@@ -3519,13 +3519,12 @@ def test_order_create_use_multiple_gift_cards(token_client, organizer, event, it
@pytest.mark.django_db @pytest.mark.django_db
def test_order_create_use_gift_card_and_payment_provider(token_client, organizer, event, item, quota, question): def test_order_create_use_gift_card_exclusive_with_payment_provider(token_client, organizer, event, item, quota, question):
res = copy.deepcopy(ORDER_CREATE_PAYLOAD) res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
res['positions'][0]['item'] = item.pk res['positions'][0]['item'] = item.pk
res['positions'][0]['answers'][0]['question'] = question.pk res['positions'][0]['answers'][0]['question'] = question.pk
with scopes_disabled(): with scopes_disabled():
customer = organizer.customers.create() customer = organizer.customers.create()
res['customer'] = customer.identifier res['customer'] = customer.identifier
res['api_meta'] = { res['api_meta'] = {
'test': 1 'test': 1
@@ -3536,21 +3535,25 @@ def test_order_create_use_gift_card_and_payment_provider(token_client, organizer
res['use_gift_cards'] = [gc.secret] res['use_gift_cards'] = [gc.secret]
res_with_payment_provider=copy.deepcopy(res)
resp = token_client.post( resp = token_client.post(
'/api/v1/organizers/{}/events/{}/orders/'.format( '/api/v1/organizers/{}/events/{}/orders/'.format(
organizer.slug, event.slug organizer.slug, event.slug
), format='json', data=res ), format='json', data=res_with_payment_provider
) )
assert resp.status_code == 201 assert resp.status_code == 400
assert resp.json() == {"use_gift_cards":["The attribute use_gift_cards is not compatible with payment_provider or payment_info"]}
with scopes_disabled(): res_with_payment_info = copy.deepcopy(res)
o = Order.objects.get(code=resp.data['code']) res_with_payment_info['payment_info'] = {"a": "b"}
assert o.status == Order.STATUS_PENDING del res_with_payment_info['payment_provider']
resp = token_client.post(
open_payment = o.payments.last() '/api/v1/organizers/{}/events/{}/orders/'.format(
assert open_payment.state == OrderPayment.PAYMENT_STATE_CREATED organizer.slug, event.slug
assert open_payment.amount == o.total - gc_value ), format='json', data=res_with_payment_info
assert open_payment.payment_provider.identifier == res['payment_provider'] )
assert resp.status_code == 400
assert resp.json() == {"use_gift_cards":["The attribute use_gift_cards is not compatible with payment_provider or payment_info"]}
@pytest.mark.django_db @pytest.mark.django_db