diff --git a/src/pretix/api/views/order.py b/src/pretix/api/views/order.py index 39c92b90c..edf0030ab 100644 --- a/src/pretix/api/views/order.py +++ b/src/pretix/api/views/order.py @@ -627,7 +627,7 @@ class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet): if request.data.get('mark_refunded', False): mark_order_refunded(refund.order, user=self.request.user if self.request.user.is_authenticated else None, auth=self.request.auth) - else: + elif not (refund.order.status == Order.STATUS_PAID and refund.order.pending_sum <= 0): refund.order.status = Order.STATUS_PENDING refund.order.set_expires( now(), diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index 560d94eac..99326de69 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -464,7 +464,7 @@ class OrderRefundProcess(OrderView): if self.request.POST.get("action") == "r": mark_order_refunded(self.order, user=self.request.user) - else: + elif not (self.order.status == Order.STATUS_PAID and self.order.pending_sum <= 0): self.order.status = Order.STATUS_PENDING self.order.set_expires( now(), @@ -750,13 +750,14 @@ class OrderRefundView(OrderView): if self.start_form.cleaned_data.get('action') == 'mark_refunded': mark_order_refunded(self.order, user=self.request.user) elif self.start_form.cleaned_data.get('action') == 'mark_pending': - self.order.status = Order.STATUS_PENDING - self.order.set_expires( - now(), - self.order.event.subevents.filter( - id__in=self.order.positions.values_list('subevent_id', flat=True)) - ) - self.order.save(update_fields=['status', 'expires']) + if not (self.order.status == Order.STATUS_PAID and self.order.pending_sum <= 0): + self.order.status = Order.STATUS_PENDING + self.order.set_expires( + now(), + self.order.event.subevents.filter( + id__in=self.order.positions.values_list('subevent_id', flat=True)) + ) + self.order.save(update_fields=['status', 'expires']) return redirect(self.get_order_url()) else: diff --git a/src/tests/control/test_orders.py b/src/tests/control/test_orders.py index 43e15b5fc..ccbcbf973 100644 --- a/src/tests/control/test_orders.py +++ b/src/tests/control/test_orders.py @@ -1078,6 +1078,33 @@ def test_process_refund(client, env): assert env[2].status == Order.STATUS_PENDING +@pytest.mark.django_db +def test_process_refund_overpaid_externally(client, env): + env[2].payments.first().confirm() + env[2].payments.create( + state='confirmed', + provider='stripe', + amount=Decimal('14.00'), + payment_date=now() + ) + assert env[2].pending_sum == -14 + r = env[2].refunds.create( + provider='stripe', + state='external', + source='external', + amount=Decimal('14.00'), + execution_date=now(), + ) + client.login(email='dummy@dummy.dummy', password='dummy') + response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/process'.format(r.pk), {}, follow=True) + assert 'alert-success' in response.rendered_content + r.refresh_from_db() + assert r.state == OrderRefund.REFUND_STATE_DONE + env[2].refresh_from_db() + assert env[2].status == Order.STATUS_PAID + assert env[2].pending_sum == 0 + + @pytest.mark.django_db def test_process_refund_invalid_state(client, env): r = env[2].refunds.create(