diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py index e12f7f418b..9af5e17ae5 100644 --- a/src/pretix/control/forms/orders.py +++ b/src/pretix/control/forms/orders.py @@ -49,7 +49,7 @@ class ExtendForm(I18nModelForm): return data -class MarkPaidForm(forms.Form): +class ConfirmPaymentForm(forms.Form): force = forms.BooleanField( label=_('Overbook quota and ignore late payment'), help_text=_('If you check this box, this operation will be performed even if it leads to an overbooked quota ' @@ -75,6 +75,20 @@ class MarkPaidForm(forms.Form): del self.fields['force'] +class MarkPaidForm(ConfirmPaymentForm): + amount = forms.DecimalField( + required=True, + max_digits=10, decimal_places=2, + localize=True, + label=_('Payment amount'), + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + change_decimal_field(self.fields['amount'], self.instance.event.currency) + self.fields['amount'].initial = max(0, self.instance.pending_sum) + + class ExporterForm(forms.Form): def clean(self): data = super().clean() diff --git a/src/pretix/control/templates/pretixcontrol/order/pay.html b/src/pretix/control/templates/pretixcontrol/order/pay.html index b22424c634..5c1eed4ab8 100644 --- a/src/pretix/control/templates/pretixcontrol/order/pay.html +++ b/src/pretix/control/templates/pretixcontrol/order/pay.html @@ -18,17 +18,21 @@
{% csrf_token %}

{% blocktrans trimmed %} - Do you really want to mark this order as paid? + Do you really want to create a manual payment for this order? {% endblocktrans %}

- {% bootstrap_form form layout='horizontal' horizontal_label_class='sr-only' horizontal_field_class='col-md-12' %} + {% bootstrap_form_errors form %} + {% bootstrap_field form.amount layout='horizontal' %} + {% if form.force %} + {% bootstrap_field form.force layout='horizontal' horizontal_label_class='sr-only' horizontal_field_class='col-md-12' %} + {% endif %}
{% trans "Cancel" %}
diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index f263b6859d..f3f7d46dfa 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -55,8 +55,8 @@ from pretix.base.views.mixins import OrderQuestionsViewMixin from pretix.base.views.tasks import AsyncAction from pretix.control.forms.filter import EventOrderFilterForm, RefundFilterForm from pretix.control.forms.orders import ( - CommentForm, ExporterForm, ExtendForm, MarkPaidForm, OrderContactForm, - OrderLocaleForm, OrderMailForm, OrderPositionAddForm, + CommentForm, ConfirmPaymentForm, ExporterForm, ExtendForm, MarkPaidForm, + OrderContactForm, OrderLocaleForm, OrderMailForm, OrderPositionAddForm, OrderPositionChangeForm, OrderRefundForm, OtherOperationsForm, ) from pretix.control.permissions import EventPermissionRequiredMixin @@ -404,7 +404,7 @@ class OrderPaymentConfirm(OrderView): @cached_property def mark_paid_form(self): - return MarkPaidForm( + return ConfirmPaymentForm( instance=self.order, data=self.request.POST if self.request.method == "POST" else None, ) @@ -675,7 +675,7 @@ class OrderTransition(OrderView): def post(self, *args, **kwargs): to = self.request.POST.get('status', '') if self.order.status in (Order.STATUS_PENDING, Order.STATUS_EXPIRED) and to == 'p' and self.mark_paid_form.is_valid(): - ps = max(0, self.order.pending_sum) + ps = self.mark_paid_form.cleaned_data['amount'] try: p = self.order.payments.get( state__in=(OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED), @@ -718,7 +718,7 @@ class OrderTransition(OrderView): messages.warning(self.request, _('The order has been marked as paid, but we were unable to send a ' 'confirmation mail.')) else: - messages.success(self.request, _('The order has been marked as paid.')) + messages.success(self.request, _('The payment has been created successfully.')) elif self.order.cancel_allowed() and to == 'c': cancel_order(self.order, user=self.request.user, send_mail=self.request.POST.get("send_email") == "on") messages.success(self.request, _('The order has been canceled.')) diff --git a/src/tests/control/test_orders.py b/src/tests/control/test_orders.py index 3bf64c145a..43e15b5fc7 100644 --- a/src/tests/control/test_orders.py +++ b/src/tests/control/test_orders.py @@ -193,6 +193,7 @@ def test_order_transition_to_paid_in_time_success(client, env): q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/transition', { + 'amount': str(env[2].pending_sum), 'status': 'p' }) o = Order.objects.get(id=env[2].id) @@ -208,7 +209,8 @@ def test_order_transition_to_paid_expired_quota_left(client, env): q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') res = client.post('/control/event/dummy/dummy/orders/FOO/transition', { - 'status': 'p' + 'status': 'p', + 'amount': str(o.pending_sum), }) o = Order.objects.get(id=env[2].id) assert res.status_code < 400 @@ -279,6 +281,7 @@ def test_order_transition(client, env, process): client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/transition?status=' + process[1]) client.post('/control/event/dummy/dummy/orders/FOO/transition', { + 'amount': str(o.pending_sum), 'status': process[1] }) o = Order.objects.get(id=env[2].id) @@ -562,7 +565,8 @@ def test_order_mark_paid_overdue_quota_blocked_by_waiting_list(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { - 'status': 'p' + 'status': 'p', + 'amount': str(o.pending_sum), }, follow=True) assert 'alert-success' in response.rendered_content o = Order.objects.get(id=env[2].id) @@ -580,6 +584,7 @@ def test_order_mark_paid_blocked(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { + 'amount': str(o.pending_sum), 'status': 'p' }, follow=True) assert 'alert-danger' in response.rendered_content @@ -588,7 +593,7 @@ def test_order_mark_paid_blocked(client, env): @pytest.mark.django_db -def test_order_mark_paid_overpaid_exired(client, env): +def test_order_mark_paid_overpaid_epxired(client, env): o = Order.objects.get(id=env[2].id) o.status = Order.STATUS_EXPIRED o.expires = now() - timedelta(days=5) @@ -601,6 +606,7 @@ def test_order_mark_paid_overpaid_exired(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'p', + 'amount': '0.00', 'force': 'on' }, follow=True) assert 'alert-success' in response.rendered_content @@ -622,6 +628,7 @@ def test_order_mark_paid_forced(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'p', + 'amount': str(o.pending_sum), 'force': 'on' }, follow=True) assert 'alert-success' in response.rendered_content