diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index 0df580de0..107e8811b 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -785,8 +785,9 @@ Creating orders * ``locale`` * ``sales_channel`` * ``payment_provider`` (optional) – The identifier of the payment provider set for this order. This needs to be an - existing payment provider. You should use ``"free"`` for free orders, and we strongly advise to use ``"manual"`` - for all orders you create as paid. + existing payment provider. You should use ``"free"`` for free orders, and we strongly advise to use ``"manual"`` + for all orders you create as paid. This field is optional when the order status is ``"n"`` or the order total is + zero, otherwise it is required. * ``payment_info`` (optional) – You can pass a nested JSON object that will be set as the internal ``info`` value of the payment object that will be created. How this value is handled is up to the payment provider and you should only use this if you know the specific payment provider in detail. Please keep in mind that the payment diff --git a/src/pretix/api/serializers/order.py b/src/pretix/api/serializers/order.py index a21fea7af..23b20d36c 100644 --- a/src/pretix/api/serializers/order.py +++ b/src/pretix/api/serializers/order.py @@ -858,6 +858,9 @@ class OrderCreateSerializer(I18nAwareModelSerializer): order.total = sum([p.price for p in order.positions.all()]) + sum([f.value for f in order.fees.all()]) order.save(update_fields=['total']) + if order.total == Decimal('0.00') and validated_data.get('status') == Order.STATUS_PAID and not payment_provider: + payment_provider = 'free' + if order.total == Decimal('0.00') and validated_data.get('status') != Order.STATUS_PAID: order.status = Order.STATUS_PAID order.save() diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index 5d8c04c00..400e56e3a 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -1656,6 +1656,25 @@ def test_order_email_optional(token_client, organizer, event, item, quota, quest assert not o.email +@pytest.mark.django_db +def test_order_create_payment_provider_optional_free(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 + res['positions'][0]['price'] = '0.00' + res['positions'][0]['status'] = 'p' + del res['payment_provider'] + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/orders/'.format( + organizer.slug, event.slug + ), format='json', data=res + ) + assert resp.status_code == 201 + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert not o.payments.exists() + + @pytest.mark.django_db def test_order_create_payment_info_optional(token_client, organizer, event, item, quota, question): res = copy.deepcopy(ORDER_CREATE_PAYLOAD)