diff --git a/doc/development/api/payment.rst b/doc/development/api/payment.rst
index b81a45808..a2a1e6050 100644
--- a/doc/development/api/payment.rst
+++ b/doc/development/api/payment.rst
@@ -83,6 +83,8 @@ The provider class
.. automethod:: order_paid_render
+ .. automethod:: order_control_render
+
Additional views
----------------
diff --git a/src/pretix/base/models.py b/src/pretix/base/models.py
index 6e985e64c..9117f4984 100644
--- a/src/pretix/base/models.py
+++ b/src/pretix/base/models.py
@@ -1488,8 +1488,8 @@ class Order(Versionable):
STATUS_CANCELLED = "c"
STATUS_REFUNDED = "r"
STATUS_CHOICE = (
- (STATUS_PAID, _("pending")),
- (STATUS_PENDING, _("paid")),
+ (STATUS_PENDING, _("pending")),
+ (STATUS_PAID, _("paid")),
(STATUS_EXPIRED, _("expired")),
(STATUS_CANCELLED, _("cancelled")),
(STATUS_REFUNDED, _("refunded"))
diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py
index 45685d861..62007953f 100644
--- a/src/pretix/base/payment.py
+++ b/src/pretix/base/payment.py
@@ -273,3 +273,17 @@ class BasePaymentProvider:
:param order: The order object
"""
return None
+
+ def order_control_render(self, request: HttpRequest, order: Order) -> str:
+ """
+ Will be called if the *event administrator* views the detail page of an order
+ which is associated with this payment provider.
+
+ It should return HTML code containing information regarding the current payment
+ status and, if applicable, next steps.
+
+ The default implementation returns the verbose name of the payment provider.
+
+ :param order: The order object
+ """
+ return _('Payment provider: %s' % self.verbose_name)
diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html
index 11ea88987..ffaead64b 100644
--- a/src/pretix/control/templates/pretixcontrol/order/index.html
+++ b/src/pretix/control/templates/pretixcontrol/order/index.html
@@ -10,6 +10,7 @@
{% blocktrans trimmed with code=order.code %}
Order details: {{ code }}
{% endblocktrans %}
+ {% include "pretixcontrol/orders/fragment_order_status.html" with order=order class="pull-right" %}
+
+
+
+ {% trans "Payment information" %}
+
+
+
+ {{ payment }}
+ {% if order.status == 'n' %}
+
{% blocktrans trimmed with date=order.expires %}
+ The payment has to be completed before {{ date }}.
+ {% endblocktrans %}
+ {% endif %}
+
+
{% endblock %}
diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py
index 13223a7db..c04b37d39 100644
--- a/src/pretix/control/views/orders.py
+++ b/src/pretix/control/views/orders.py
@@ -1,8 +1,10 @@
from itertools import groupby
from django.db.models import Q
+from django.utils.functional import cached_property
from django.views.generic import ListView, DetailView
from pretix.base.models import Order
+from pretix.base.signals import register_payment_providers
from pretix.control.permissions import EventPermissionRequiredMixin
@@ -31,10 +33,19 @@ class OrderDetail(EventPermissionRequiredMixin, DetailView):
code=self.kwargs['code'].upper()
)
+ @cached_property
+ def payment_provider(self):
+ responses = register_payment_providers.send(self.request.event)
+ for receiver, response in responses:
+ provider = response(self.request.event)
+ if provider.identifier == self.object.payment_provider:
+ return provider
+
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['items'] = self.get_items()
ctx['event'] = self.request.event
+ ctx['payment'] = self.payment_provider.order_control_render(self.request, self.object)
return ctx
def get_items(self):
diff --git a/src/pretix/plugins/banktransfer/payment.py b/src/pretix/plugins/banktransfer/payment.py
index 781b4a7d4..886de5352 100644
--- a/src/pretix/plugins/banktransfer/payment.py
+++ b/src/pretix/plugins/banktransfer/payment.py
@@ -1,4 +1,5 @@
from collections import OrderedDict
+import json
from django.template import Context
from django.template.loader import get_template
from django.utils.translation import ugettext_lazy as _
@@ -45,3 +46,14 @@ class BankTransfer(BasePaymentProvider):
template = get_template('pretixplugins/banktransfer/pending.html')
ctx = Context({'request': request, 'order': order, 'settings': self.settings})
return template.render(ctx)
+
+ def order_control_render(self, request, order) -> str:
+ if order.payment_info:
+ payment_info = json.loads(order.payment_info)
+ payment_info['amount'] /= 100
+ else:
+ payment_info = None
+ template = get_template('pretixplugins/banktransfer/control.html')
+ ctx = Context({'request': request, 'event': self.event, 'settings': self.settings,
+ 'payment_info': payment_info, 'order': order})
+ return template.render(ctx)
diff --git a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/control.html b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/control.html
new file mode 100644
index 000000000..cc72d6b82
--- /dev/null
+++ b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/control.html
@@ -0,0 +1,28 @@
+{% load i18n %}
+
+{% if payment_info and order.status == "p" %}
+ {% blocktrans trimmed %}
+ This order has been paid via bank transfer.
+ {% endblocktrans %}
+
+
+ - {% trans "Bank account" %}
+ - {{ payment_info.account }}
+ - {% trans "Payer name" %}
+ - {{ payment_info.name }}
+ - {% trans "Total value" %}
+ - {{ payment_info.value }}
+ - {% trans "Payment date" %}
+ - {{ payment_info.date }}
+ - {% trans "Reference" %}
+ - {{ payment_info.reference }}
+
+{% else %}
+ {% blocktrans trimmed %}
+ This order has been planned to be paid via bank transfer, but no payment has been received yet.
+ {% endblocktrans %}
+
+ - {% trans "Reference code" %}
+ - {{ event.slug|upper }}{{ order.code }}
+
+{% endif %}
diff --git a/src/pretix/plugins/paypal/payment.py b/src/pretix/plugins/paypal/payment.py
index fb6ed2b8e..091da3e07 100644
--- a/src/pretix/plugins/paypal/payment.py
+++ b/src/pretix/plugins/paypal/payment.py
@@ -153,7 +153,7 @@ class Paypal(BasePaymentProvider):
self.init_api()
payment = paypalrestsdk.Payment.find(request.session.get('payment_paypal_id'))
- if str(payment.transactions[0].amount.total) != str(order.total) or payment.transactions[1].amount.currency != \
+ if str(payment.transactions[0].amount.total) != str(order.total) or payment.transactions[0].amount.currency != \
self.event.currency:
messages.error(request, _('We were unable to process your payment. See below for details on how to '
'proceed.'))
@@ -169,7 +169,7 @@ class Paypal(BasePaymentProvider):
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as soon as the '
'payment completed.'))
order = order.clone()
- order.payment_info = str(payment)
+ order.payment_info = json.dumps(payment.to_dict())
order.save()
return
@@ -179,7 +179,7 @@ class Paypal(BasePaymentProvider):
logger.error('Invalid state: %s' % str(payment))
return
- order.mark_paid('paypal', str(payment))
+ order.mark_paid('paypal', json.dumps(payment.to_dict()))
messages.success(request, _('We successfully received your payment. Thank you!'))
return None
@@ -194,3 +194,13 @@ class Paypal(BasePaymentProvider):
ctx = Context({'request': request, 'event': self.event, 'settings': self.settings,
'retry': retry, 'order': order})
return template.render(ctx)
+
+ def order_control_render(self, request, order) -> str:
+ if order.payment_info:
+ payment_info = json.loads(order.payment_info)
+ else:
+ payment_info = None
+ template = get_template('pretixplugins/paypal/control.html')
+ ctx = Context({'request': request, 'event': self.event, 'settings': self.settings,
+ 'payment_info': payment_info, 'order': order})
+ return template.render(ctx)
diff --git a/src/pretix/plugins/paypal/templates/pretixplugins/paypal/control.html b/src/pretix/plugins/paypal/templates/pretixplugins/paypal/control.html
new file mode 100644
index 000000000..98a569d9e
--- /dev/null
+++ b/src/pretix/plugins/paypal/templates/pretixplugins/paypal/control.html
@@ -0,0 +1,29 @@
+{% load i18n %}
+
+{% if payment_info %}
+ {% if order.status == "p" %}
+ {% blocktrans trimmed %}
+ This order has been paid via PayPal.
+ {% endblocktrans %}
+ {% else %}
+ {% blocktrans trimmed %}
+ This order has been planned to be paid via PayPal, but the payment has not yet been completed.
+ {% endblocktrans %}
+ {% endif %}
+
+ - {% trans "Payment ID" %}
+ - {{ payment_info.id }}
+ - {% trans "Payer" %}
+ - {{ payment_info.payer.payer_info.email }}
+ - {% trans "Last update" %}
+ - {{ payment_info.update_time }}
+ - {% trans "Total value" %}
+ - {{ payment_info.transactions.0.amount.total }}
+ - {% trans "Currency" %}
+ - {{ payment_info.transactions.0.amount.currency }}
+
+{% else %}
+ {% blocktrans trimmed %}
+ This order has been planned to be paid via PayPal, but the payment has not yet been completed.
+ {% endblocktrans %}
+{% endif %}
diff --git a/src/pretix/plugins/stripe/payment.py b/src/pretix/plugins/stripe/payment.py
index ff6a4438e..a6b70c591 100644
--- a/src/pretix/plugins/stripe/payment.py
+++ b/src/pretix/plugins/stripe/payment.py
@@ -1,4 +1,5 @@
from collections import OrderedDict
+import json
import logging
from django.contrib import messages
from django.template import Context
@@ -82,3 +83,14 @@ class Stripe(BasePaymentProvider):
ctx = Context({'request': request, 'event': self.event, 'settings': self.settings,
'order': order})
return template.render(ctx)
+
+ def order_control_render(self, request, order) -> str:
+ if order.payment_info:
+ payment_info = json.loads(order.payment_info)
+ payment_info['amount'] /= 100
+ else:
+ payment_info = None
+ template = get_template('pretixplugins/stripe/control.html')
+ ctx = Context({'request': request, 'event': self.event, 'settings': self.settings,
+ 'payment_info': payment_info, 'order': order})
+ return template.render(ctx)
diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/control.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/control.html
new file mode 100644
index 000000000..faf50b4b3
--- /dev/null
+++ b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/control.html
@@ -0,0 +1,33 @@
+{% load i18n %}
+
+{% if payment_info %}
+ {% if order.status == "p" %}
+ {% blocktrans trimmed %}
+ This order has been paid via Stripe.
+ {% endblocktrans %}
+ {% else %}
+ {% blocktrans trimmed %}
+ This order has been planned to be paid via Stripe, but the payment has not yet been completed.
+ {% endblocktrans %}
+ {% endif %}
+
+ - {% trans "Charge ID" %}
+ - {{ payment_info.id }}
+ - {% trans "Card type" %}
+ - {{ payment_info.source.brand }}
+ - {% trans "Card number" %}
+ - **** **** **** {{ payment_info.source.last4 }}
+ - {% trans "Payer name" %}
+ - {{ payment_info.source.name }}
+ - {% trans "Total value" %}
+ - {{ payment_info.amount|floatformat:2 }}
+ - {% trans "Currency" %}
+ - {{ payment_info.currency|upper }}
+ - {% trans "Status" %}
+ - {{ payment_info.status }}
+
+{% else %}
+ {% blocktrans trimmed %}
+ This order has been planned to be paid via Stripe, but the payment has not yet been completed.
+ {% endblocktrans %}
+{% endif %}