forked from CGM_Public/pretix_original
Documentation for the payment provider plugin API
This commit is contained in:
@@ -3,10 +3,12 @@ from decimal import Decimal
|
||||
from django import forms
|
||||
|
||||
from django.forms import Form
|
||||
from django.http import HttpRequest
|
||||
from django.template import Context
|
||||
from django.template.loader import get_template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from pretix.base.forms import SettingsForm
|
||||
from pretix.base.models import Order
|
||||
|
||||
from pretix.base.settings import SettingsSandbox
|
||||
|
||||
@@ -66,11 +68,30 @@ class BasePaymentProvider:
|
||||
def settings_form_fields(self) -> dict:
|
||||
"""
|
||||
When the event's administrator administrator visits the event configuration
|
||||
page,
|
||||
A dictionary. The keys should be (unprefixed) EventSetting keys,
|
||||
the values should be corresponding django form fields.
|
||||
page, this method is called to return the configuration fields available.
|
||||
|
||||
We suggest returning a collections.OrderedDict object instead of a dict.
|
||||
It should therefore return a dictionary where the keys should be (unprefixed)
|
||||
settings keys and the values should be corresponding Django form fields.
|
||||
|
||||
The default implementation returns the appropriate fields for the ``_enabled``,
|
||||
``_fee_abs`` and ``_fee_percent`` settings mentioned above.
|
||||
|
||||
We suggest that you return an ``OrderedDict`` object instead of a dictionary
|
||||
and make use of the default implementation. Your implementation could look
|
||||
like this::
|
||||
|
||||
@property
|
||||
def settings_form_fields(self):
|
||||
return OrderedDict(
|
||||
list(super().settings_form_fields.items()) + [
|
||||
('bank_details',
|
||||
forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
label=_('Bank account details'),
|
||||
required=False
|
||||
))
|
||||
]
|
||||
)
|
||||
"""
|
||||
return OrderedDict([
|
||||
('_enabled',
|
||||
@@ -96,18 +117,20 @@ class BasePaymentProvider:
|
||||
@property
|
||||
def checkout_form_fields(self) -> dict:
|
||||
"""
|
||||
A dictionary. The keys should be unprefixed field names,
|
||||
the values should be corresponding django form fields.
|
||||
This is used by the default implementation of :py:meth:`checkout_form`.
|
||||
It should return an object similar to :py:attr:`settings_form_fields`.
|
||||
|
||||
We suggest returning a collections.OrderedDict object instead of a dict.
|
||||
The default implementation returns an empty dictionary.
|
||||
"""
|
||||
# TODO: Proper handling of required=True fields in HTML
|
||||
return {}
|
||||
|
||||
def checkout_form(self, request) -> Form:
|
||||
def checkout_form(self, request: HttpRequest) -> Form:
|
||||
"""
|
||||
Returns the Form object of the form that should be displayed when the
|
||||
user selects this provider as his payment method.
|
||||
This is called by the default implementation of :py:meth:`checkout_form_render`
|
||||
to obtain the form that is displayed to the user during the checkout
|
||||
process. The default implementation constructs the form using
|
||||
:py:attr:`checkout_form_fields` and sets appropriate prefixes for the form
|
||||
and all fields and fills the form with data form the user's session.
|
||||
"""
|
||||
form = Form(
|
||||
data=(request.POST if request.method == 'POST' else None),
|
||||
@@ -121,10 +144,15 @@ class BasePaymentProvider:
|
||||
form.fields = self.checkout_form_fields
|
||||
return form
|
||||
|
||||
def checkout_form_render(self, request) -> str:
|
||||
def checkout_form_render(self, request: HttpRequest) -> str:
|
||||
"""
|
||||
Returns the HTML of the form that should be displayed when the user
|
||||
selects this provider as his payment method.
|
||||
When the user selects this provider as his prefered payment method,
|
||||
he will be shown the HTML you return from this method.
|
||||
|
||||
The default implementation will call :py:meth:`checkout_form`
|
||||
and render the returned form. If your payment method doesn't require
|
||||
the user to fill out form fields, you should just return a paragraph
|
||||
of explainatory text.
|
||||
"""
|
||||
form = self.checkout_form(request)
|
||||
template = get_template('pretixpresale/event/checkout_payment_form_default.html')
|
||||
@@ -133,23 +161,53 @@ class BasePaymentProvider:
|
||||
|
||||
def checkout_confirm_render(self, request) -> str:
|
||||
"""
|
||||
Returns the HTML that should be displayed when the user selected this provider
|
||||
on the 'confirm order' page.
|
||||
If the user successfully filled in his payment data, he will be redirected
|
||||
to a confirmation page which lists all details of his order for a final review.
|
||||
This method should return the HTML which should be displayed inside the
|
||||
'Payment' box on this page.
|
||||
|
||||
In most cases, this should include a short summary of the user's input and
|
||||
a short explaination on how the payment process will continue.
|
||||
"""
|
||||
raise NotImplementedError() # NOQA
|
||||
|
||||
def checkout_prepare(self, request, cart) -> "bool|HttpResponse":
|
||||
def checkout_prepare(self, request: HttpRequest, cart: dict) -> "bool|str":
|
||||
"""
|
||||
Will be called if the user selects this provider as his payment method.
|
||||
If the payment provider provides a form to the user to enter payment data,
|
||||
this method should at least store the user's input into his session.
|
||||
Will be called after the user selected this provider as his payment method.
|
||||
If you provided a form to the user to enter payment data, this method should
|
||||
at least store the user's input into his session.
|
||||
|
||||
It should return True or False, depending of the validity of the user's input,
|
||||
if the frontend should continue with default behaviour, or a redirect URL,
|
||||
if you need special behaviour.
|
||||
This method should return ``False``, if the user's input was invalid, ``True``
|
||||
if the input was valid and the frontend should continue with default behaviour
|
||||
or a string containing an URL, if the user should be redirected somewhere else.
|
||||
|
||||
On errors, it should use Django's message framework to display an error message
|
||||
On errors, you should use Django's message framework to display an error message
|
||||
to the user (or the normal form validation error messages).
|
||||
|
||||
The default implementation stores the input into the form returned by
|
||||
:py:meth:`checkout_form` in the user's session.
|
||||
|
||||
If your payment method requires you to redirect the user to an external provider,
|
||||
this might be the place to do so.
|
||||
|
||||
.. IMPORTANT:: If this is called, the user has not yet confirmed his or her order.
|
||||
You may NOT do anything which actually moves money.
|
||||
|
||||
:param cart: This dictionary contains at least the following keys:
|
||||
|
||||
positions:
|
||||
A list of ``CartPosition`` objects that are annotated with the special
|
||||
attributes ``count`` and ``total`` because multiple objects of the
|
||||
same content are grouped into one.
|
||||
|
||||
raw:
|
||||
The raw list of ``CartPosition`` objects in the users cart
|
||||
|
||||
total:
|
||||
The overall total *including* the fee for the payment method.
|
||||
|
||||
payment_fee:
|
||||
The fee for the payment method.
|
||||
"""
|
||||
form = self.checkout_form(request)
|
||||
if form.is_valid():
|
||||
@@ -159,49 +217,58 @@ class BasePaymentProvider:
|
||||
else:
|
||||
return False
|
||||
|
||||
def checkout_is_valid_session(self, request) -> bool:
|
||||
def checkout_is_valid_session(self, request: HttpRequest) -> bool:
|
||||
"""
|
||||
This is called at the time the user tries to place the order. It should return
|
||||
True, if the user's session is valid and all data your payment provider requires
|
||||
``True``, if the user's session is valid and all data your payment provider requires
|
||||
in future steps is present.
|
||||
"""
|
||||
raise NotImplementedError() # NOQA
|
||||
|
||||
def checkout_perform(self, request, order) -> str:
|
||||
def checkout_perform(self, request: HttpRequest, order: Order) -> str:
|
||||
"""
|
||||
Will be called if the user submitted his order successfully to initiate the
|
||||
payment process.
|
||||
After the user confirmed his purchase, this method will be called to complete
|
||||
the payment process. This is the place to actually move the money, if applicable.
|
||||
If you need any speical behaviour, you can return a string
|
||||
containing an URL the user will be redirected to. If you are done with your process
|
||||
you should return the user to the order's detail page.
|
||||
|
||||
It should return a custom redirct URL, if you need special behaviour, or None to
|
||||
continue with default behaviour.
|
||||
If the payment is completed, you should call ``order.mark_paid(provider, info)``
|
||||
with ``provider`` being your :py:attr:`identifier` and ``info`` being any string
|
||||
you might want to store for later usage. Please note, that if you want to store
|
||||
something inside ``order.payment_info``, please do a ``order = order.clone()`` before
|
||||
modifying or saving the order object.
|
||||
|
||||
On errors, it should use Django's message framework to display an error message
|
||||
to the user (or the normal form validation error messages).
|
||||
The default implementation just returns ``None`` and therefore leaves the
|
||||
order unpaid. The user will be redirected to the order's detail page by default.
|
||||
|
||||
On errors, you should use Django's message framework to display an error message
|
||||
to the user.
|
||||
|
||||
:param order: The order object
|
||||
"""
|
||||
return None
|
||||
|
||||
def order_pending_render(self, request, order) -> str:
|
||||
def order_pending_render(self, request: HttpRequest, order: Order) -> str:
|
||||
"""
|
||||
Will be called if the user views the detail page of an unpaid order which is
|
||||
associated with this payment provider.
|
||||
If the user visits a detail page of an order which has not yet been paid but
|
||||
this payment method was selected during checkout, this method will be called
|
||||
to provide HTML content for the 'payment' box on the page.
|
||||
|
||||
It should return HTML code which should be displayed to the user. It should contian
|
||||
instructions on how to continue with the payment process, either in form of text
|
||||
or buttons/links/etc.
|
||||
It should contain instructions on how to continue with the payment process,
|
||||
either in form of text or buttons/links/etc.
|
||||
|
||||
:param order: The order object
|
||||
"""
|
||||
raise NotImplementedError() # NOQA
|
||||
|
||||
def order_paid_render(self, request, order) -> str:
|
||||
def order_paid_render(self, request: HttpRequest, order: Order) -> str:
|
||||
"""
|
||||
Will be called if the user views the detail page of an paid order which is
|
||||
associated with this payment provider.
|
||||
|
||||
It should return HTML code which should be displayed to the user or None,
|
||||
if there is nothing to say.
|
||||
if there is nothing to say (like the default implementation does).
|
||||
|
||||
:param order: The order object
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user