diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 60f90dac40..a62ed30c0e 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -188,6 +188,17 @@ class Order(LoggedModel): except TypeError: return None + @property + def payment_refund_sum(self): + payment_sum = self.payments.filter( + state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED) + ).aggregate(s=Sum('amount'))['s'] or Decimal('0.00') + refund_sum = self.refunds.filter( + state__in=(OrderRefund.REFUND_STATE_DONE, OrderRefund.REFUND_STATE_TRANSIT, + OrderRefund.REFUND_STATE_CREATED) + ).aggregate(s=Sum('amount'))['s'] or Decimal('0.00') + return payment_sum - refund_sum + @property def pending_sum(self): total = self.total diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py index e0489c71fe..e12f7f418b 100644 --- a/src/pretix/control/forms/orders.py +++ b/src/pretix/control/forms/orders.py @@ -375,9 +375,11 @@ class OrderRefundForm(forms.Form): self.order = kwargs.pop('order') super().__init__(*args, **kwargs) change_decimal_field(self.fields['partial_amount'], self.order.event.currency) + if self.order.status in (Order.STATUS_REFUNDED, Order.STATUS_CANCELED): + del self.fields['action'] def clean_partial_amount(self): - max_amount = self.order.total - self.order.pending_sum + max_amount = self.order.payment_refund_sum val = self.cleaned_data.get('partial_amount') if val is not None and (val > max_amount or val <= 0): raise ValidationError(_('The refund amount needs to be positive and less than {}.').format(max_amount)) diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html index 57b09e7588..4d231ec354 100644 --- a/src/pretix/control/templates/pretixcontrol/order/index.html +++ b/src/pretix/control/templates/pretixcontrol/order/index.html @@ -50,10 +50,7 @@ {% trans "Cancel order" %} {% endif %} - {% if order.status == 'p' %} - - {% endif %} - {% if overpaid|add:order.total != 0 %} + {% if order.payment_refund_sum > 0 %} {% trans "Create a refund" %} diff --git a/src/pretix/control/templates/pretixcontrol/order/refund_start.html b/src/pretix/control/templates/pretixcontrol/order/refund_start.html index 54f450957c..f9048c79fe 100644 --- a/src/pretix/control/templates/pretixcontrol/order/refund_start.html +++ b/src/pretix/control/templates/pretixcontrol/order/refund_start.html @@ -35,10 +35,12 @@
- + {% if form.action %} + + {% endif %}
{% csrf_token %} diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index 41e34ab60f..8d5e91ddbb 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -442,7 +442,7 @@ class OrderRefundView(OrderView): data=self.request.POST if self.request.method == "POST" else None, prefix='start', initial={ - 'partial_amount': self.order.total - self.order.pending_sum, + 'partial_amount': self.order.payment_refund_sum, 'action': ( 'mark_pending' if self.order.status == Order.STATUS_PAID else 'do_nothing' @@ -465,7 +465,7 @@ class OrderRefundView(OrderView): # Algorithm to choose which payments are to be refunded to create the least hassle if self.start_form.cleaned_data.get('mode') == 'full': - to_refund = full_refund = self.order.total - self.order.pending_sum + to_refund = full_refund = self.order.payment_refund_sum else: to_refund = full_refund = self.start_form.cleaned_data.get('partial_amount') diff --git a/src/tests/control/test_orders.py b/src/tests/control/test_orders.py index 56f2b8b47c..471a807607 100644 --- a/src/tests/control/test_orders.py +++ b/src/tests/control/test_orders.py @@ -1402,7 +1402,10 @@ def test_refund_paid_order_automatically(client, env, monkeypatch): def charge_retr(*args, **kwargs): def refund_create(amount): - pass + r = MockedCharge() + r.id = 'foo' + r.status = 'succeeded' + return r c = MockedCharge() c.refunds.create = refund_create