From 5664177bbbe960b18522d57bc044538193e73faa Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 20 Mar 2015 23:20:12 +0100 Subject: [PATCH] Order details: Display payment information --- doc/development/api/payment.rst | 2 ++ src/pretix/base/models.py | 4 +-- src/pretix/base/payment.py | 14 ++++++++ .../templates/pretixcontrol/order/index.html | 16 +++++++++ src/pretix/control/views/orders.py | 11 +++++++ src/pretix/plugins/banktransfer/payment.py | 12 +++++++ .../pretixplugins/banktransfer/control.html | 28 ++++++++++++++++ src/pretix/plugins/paypal/payment.py | 16 +++++++-- .../pretixplugins/paypal/control.html | 29 ++++++++++++++++ src/pretix/plugins/stripe/payment.py | 12 +++++++ .../pretixplugins/stripe/control.html | 33 +++++++++++++++++++ 11 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/control.html create mode 100644 src/pretix/plugins/paypal/templates/pretixplugins/paypal/control.html create mode 100644 src/pretix/plugins/stripe/templates/pretixplugins/stripe/control.html diff --git a/doc/development/api/payment.rst b/doc/development/api/payment.rst index b81a458084..a2a1e60500 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 6e985e64c0..9117f49847 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 45685d8610..62007953f7 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 11ea889878..ffaead64bc 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" %}
@@ -78,4 +79,19 @@
+
+
+

+ {% 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 13223a7db4..c04b37d39e 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 781b4a7d47..886de53525 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 0000000000..cc72d6b825 --- /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 fb6ed2b8e4..091da3e071 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 0000000000..98a569d9ec --- /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 ff6a4438e0..a6b70c591a 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 0000000000..faf50b4b35 --- /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 %}