mirror of
https://github.com/pretix/pretix.git
synced 2026-08-18 12:06:26 +00:00
Documentation for the payment provider plugin API
This commit is contained in:
@@ -8,21 +8,119 @@ In this document, we will walk through the creation of a payment provider plugin
|
||||
|
||||
Please read :ref:`Creating a plugin <pluginsetup>` first, if you haven't already.
|
||||
|
||||
The signal
|
||||
----------
|
||||
Provider registration
|
||||
---------------------
|
||||
|
||||
The payment provider API does not make a lot of usage from signals, however, it
|
||||
does use a signal to get a list of all available payment providers. Your plugin
|
||||
should listen for this signal and return the subclass of ``pretix.base.payment.PaymentProvider``
|
||||
should listen for this signal and return the subclass of ``pretix.base.payment.BasePaymentProvider``
|
||||
that we'll soon create::
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from pretix.base.signals import register_payment_providers
|
||||
|
||||
from .payment import BankTransfer
|
||||
from .payment import Paypal
|
||||
|
||||
|
||||
@receiver(register_payment_providers)
|
||||
def register_payment_provider(sender, **kwargs):
|
||||
return BankTransfer
|
||||
return Paypal
|
||||
|
||||
|
||||
The provider class
|
||||
------------------
|
||||
|
||||
.. class:: pretix.base.payment.BasePaymentProvider
|
||||
|
||||
The central object of each payment provider is the subclass of ``BasePaymentProvider``
|
||||
we already mentioned above. In this section, we will discuss it's interface in detail.
|
||||
|
||||
.. py:attribute:: BasePaymentProvider.event
|
||||
|
||||
The default constructor sets this property to the event we are currently
|
||||
working for.
|
||||
|
||||
.. py:attribute:: BasePaymentProvider.settings
|
||||
|
||||
The default constructor sets this property to a ``SettingsSandbox`` object. You can
|
||||
use this object to store settings using its ``get`` and ``set`` methods. All settings
|
||||
you store are transparently prefixed, so you get your very own settings namespace.
|
||||
|
||||
.. autoattribute:: identifier
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: verbose_name
|
||||
|
||||
This is an abstract attribute, you **must** override this!
|
||||
|
||||
.. autoattribute:: is_enabled
|
||||
|
||||
.. automethod:: calculate_fee
|
||||
|
||||
.. autoattribute:: settings_form_fields
|
||||
|
||||
.. automethod:: checkout_form_render
|
||||
|
||||
.. automethod:: checkout_form
|
||||
|
||||
.. autoattribute:: checkout_form_fields
|
||||
|
||||
.. automethod:: checkout_prepare
|
||||
|
||||
.. automethod:: checkout_is_valid_session
|
||||
|
||||
.. automethod:: checkout_confirm_render
|
||||
|
||||
This is an abstract method, you **must** override this!
|
||||
|
||||
.. automethod:: checkout_perform
|
||||
|
||||
.. automethod:: order_pending_render
|
||||
|
||||
This is an abstract method, you **must** override this!
|
||||
|
||||
.. automethod:: order_paid_render
|
||||
|
||||
|
||||
Additional views
|
||||
----------------
|
||||
|
||||
For most simple payment providers it is more than sufficient to implement
|
||||
some of the :py:class:`BasePaymentProvider` methods. However, in some cases
|
||||
it is necessary to introduce additional views. One example is the PayPal
|
||||
provider. It redirects the user to a paypal website in the
|
||||
:py:meth:`BasePaymentProvider.checkout_prepare`` step of the checkout process
|
||||
and provides PayPal with an URL to redirect back to. This URL points to a
|
||||
view which looks roughly like this::
|
||||
|
||||
@login_required
|
||||
def success(request):
|
||||
pid = request.GET.get('paymentId')
|
||||
payer = request.GET.get('PayerID')
|
||||
# We stored some information in the session in checkout_prepare(),
|
||||
# let's compare the new information to double-check that this is about
|
||||
# the same payment
|
||||
if pid == request.session['payment_paypal_id']:
|
||||
# Save the new information to the user's session
|
||||
request.session['payment_paypal_payer'] = payer
|
||||
try:
|
||||
# Redirect back to the confirm page. We chose to save the
|
||||
# event ID in the user's session. We could also put this
|
||||
# information into an URL parameter.
|
||||
event = Event.objects.current.get(identity=request.session['payment_paypal_event'])
|
||||
return redirect(reverse('presale:event.checkout.confirm', kwargs={
|
||||
'event': event.slug,
|
||||
'organizer': event.organizer.slug,
|
||||
}))
|
||||
except Event.DoesNotExist:
|
||||
pass # TODO: Display error message
|
||||
else:
|
||||
pass # TODO: Display error message
|
||||
|
||||
If you do not want to provide a view of your own, you could even let PayPal
|
||||
redirect directly back to the confirm page and handle the query parameters
|
||||
inside :py:meth:`BasePaymentProvider.checkout_is_valid_session``. However,
|
||||
because some external providers (not PayPal) force you to have a *constant*
|
||||
redirect URL, it might be necessary to define custom views.
|
||||
|
||||
@@ -13,23 +13,45 @@ require two steps to install:
|
||||
* Add it to the ``INSTALLED_APPS`` setting of Django in ``pretix/settings.py``
|
||||
* Perform database migrations by using ``python manage.py migrate``
|
||||
|
||||
The communication between pretix and the plugins happens via Django's
|
||||
`signal dispatcher`_ pattern. The core modules of pretix, ``pretixbase``,
|
||||
The communication between pretix and the plugins happens mostly using Django's
|
||||
`signal dispatcher`_ feature. The core modules of pretix, ``pretixbase``,
|
||||
``pretixcontrol`` and ``pretixpresale`` expose a number of signals which are documented
|
||||
on the next pages.
|
||||
|
||||
.. _`pluginsetup`:
|
||||
|
||||
Creating a plugin
|
||||
-----------------
|
||||
To create a new plugin, create a new python package which must be a vaild `Django app`_
|
||||
and must contain plugin metadata, as described below.
|
||||
|
||||
To create a new plugin, create a new python package.
|
||||
The following pages go into detail about the several types of plugins currently
|
||||
supported. While these instructions don't assume that you know a lot about pretix,
|
||||
they do assume that you have prior knowledge about Django (e.g. it's view layer,
|
||||
how it's ORM works, etc.).
|
||||
|
||||
Inside your newly created folder, you'll probably need the three python modules ``__init__.py``,
|
||||
``models.py`` and ``signals.py``, although this is up to you. You can take the following
|
||||
example, taken from the time restriction module (see next chapter) as a template for your
|
||||
``__init__.py`` module::
|
||||
Plugin metadata
|
||||
---------------
|
||||
|
||||
The plugin metadata lives inside a ``PretixPluginMeta`` class inside your app's
|
||||
configuration class. The metadata class must define the following attributes:
|
||||
|
||||
``type`` (``pretix.base.plugins.PluginType``):
|
||||
The type of plugin. Currently available: ``RESTRICTION``, ``PAYMENT``
|
||||
|
||||
``name`` (``str``):
|
||||
The human-readable name of your plugin
|
||||
|
||||
``author`` (``str``):
|
||||
Your name
|
||||
|
||||
``version`` (``str``):
|
||||
A human-readable version code of your plugin
|
||||
|
||||
``description`` (``str``):
|
||||
A more verbose description of what your plugin does.
|
||||
|
||||
A working example would be::
|
||||
|
||||
# file: pretix/plugins/timerestriction/__init__.py
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from pretix.base.plugins import PluginType
|
||||
@@ -48,21 +70,36 @@ example, taken from the time restriction module (see next chapter) as a template
|
||||
"of a given item or variation to a certain timeframe " +
|
||||
"or change its price during a certain period.")
|
||||
|
||||
def ready(self):
|
||||
from . import signals # NOQA
|
||||
|
||||
default_app_config = 'pretix.plugins.timerestriction.TimeRestrictionApp'
|
||||
|
||||
.. IMPORTANT::
|
||||
You have to implement a ``PretixPluginMeta`` class like in the example to make your
|
||||
plugin available to the users.
|
||||
|
||||
Currently, the ``PluginType`` enum has the following values defined:
|
||||
Signals
|
||||
-------
|
||||
|
||||
* ``RESTRICTION``
|
||||
* ``PAYMENT``
|
||||
The various components of pretix define a number of signals which your plugin can
|
||||
listen for. We will go into the details of the different signals in the following
|
||||
pages. We suggest that you put your signal receivers into a ``signals`` submodule
|
||||
of your plugin. You should extend your ``AppConfig`` (see above) by the following
|
||||
method to make your receivers available::
|
||||
|
||||
The next pages provide details on their usage.
|
||||
class TimeRestrictionApp(AppConfig):
|
||||
…
|
||||
|
||||
def ready(self):
|
||||
from . import signals # NOQA
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
Your plugin may define custom views. If you put an ``urls`` submodule into your
|
||||
plugin module, pretix will automatically import it and include it into the root
|
||||
URL configuration.
|
||||
|
||||
.. WARNING:: If you define custom URLs and views, you are currently on your own
|
||||
with checking that the calling user is logged in, has appropriate permissions,
|
||||
etc. We plan on providing native support for this in a later version.
|
||||
|
||||
.. _Django app: https://docs.djangoproject.com/en/1.7/ref/applications/
|
||||
.. _signal dispatcher: https://docs.djangoproject.com/en/1.7/topics/signals/
|
||||
.. _namespace packages: http://legacy.python.org/dev/peps/pep-0420/
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
Writing a restriction plugin
|
||||
============================
|
||||
|
||||
Please make sure you have read and understood the :ref:`basic idea being pretix's restrictions
|
||||
<restrictionconcept>`. In this document, we will walk through the creation of a restriction
|
||||
plugin using the example of a restriction by date and time.
|
||||
Please make sure you have read and understood the :ref:`basic idea <restrictionconcept>` behind
|
||||
what pretix calls *restrictions*. In this document, we will walk through the creation of a
|
||||
restriction plugin using the example of a restriction by date and time.
|
||||
|
||||
Also, read :ref:`Creating a plugin <pluginsetup>` first.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user