Billing gateways

Adding a new gateway to fleio

The following gateways already exist in Fleio: Paypal, Stripe, Romcard and PayU. Those are located in /var/webapps/fleio/ project/fleio/billing/gateways/ (location is available after running fleio bash command) and you can find some inspiration from there when adding your desired gateway. To configure an existing gateway read the gateways configuration documentation

A gateway template exists here https://github.com/fleio/gateway-template, however the following instructions show information about each step required to create a new gateway template. Also, please note that each gateway has its own implementation and the following information might not be all that needs to be done so that the new gateway to work properly. For implementing a new gateway we highly recommend to talk to a python developer.

First, we will have to change directory to /home/fleio/compose and create a new directory where we will place our custom gateway files:

cd /home/fleio/compose
mkdir custombackend
cd custombackend
git clone https://github.com/fleio/gateway-template.git

Create the following Dockerfile related files in /home/fleio/compose/custombackend/ with the code from below:

Important

Depending on edition, you might need to add _web or _openstack on the 4th line of each Dockerfile e.g. FROM ${FLEIO_DOCKER_HUB}/fleio_backend${FLEIO_RELEASE_SUFFIX} will be FROM ${FLEIO_DOCKER_HUB}/fleio_backend_openstack${FLEIO_RELEASE_SUFFIX} or FROM ${FLEIO_DOCKER_HUB}/fleio_backend_web${FLEIO_RELEASE_SUFFIX}

  • Dockerfile-backend

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_backend${FLEIO_RELEASE_SUFFIX}

ENV INSTALL_PATH="/var/webapps/fleio"

COPY --chown=fleio:fleio gateway-template "$INSTALL_PATH/project/fleio/billing/gateways/"
  • Dockerfile-updated

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_updated${FLEIO_RELEASE_SUFFIX}

ENV INSTALL_PATH="/var/webapps/fleio"

COPY --chown=fleio:fleio gateway-template "$INSTALL_PATH/project/fleio/billing/gateways/"
  • Dockerfile-celery

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_celery${FLEIO_RELEASE_SUFFIX}

ENV INSTALL_PATH="/var/webapps/fleio"

COPY --chown=fleio:fleio gateway-template "$INSTALL_PATH/project/fleio/billing/gateways/"
  • Dockerfile-celerybeat

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_celerybeat${FLEIO_RELEASE_SUFFIX}

ENV INSTALL_PATH="/var/webapps/fleio"

COPY --chown=fleio:fleio gateway-template "$INSTALL_PATH/project/fleio/billing/gateways/"
  • Dockerfile-operations

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_operations${FLEIO_RELEASE_SUFFIX}

ENV INSTALL_PATH="/var/webapps/fleio"

COPY --chown=fleio:fleio gateway-template "$INSTALL_PATH/project/fleio/billing/gateways/"

This will add the newgateway folder (with its content) in /var/webapps/fleio/project/fleio/billing/gateways/ to all needed images which will be built in the next step.

Add this to your /home/fleio/compose/docker-compose.override.yml file:

# Add here your Docker Compose customizations
# docker-compose.override.yml is not overwritten by Fleio
# (while docker-compose.yml may be OVERWRITTEN on Fleio upgrades)

services:
  backend:
    build:
      context: ./customgateway/
      dockerfile: Dockerfile-backend
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_backend_custom
    pull_policy: never

  updated:
    build:
      context: ./customgateway/
      dockerfile: Dockerfile-updated
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_updated_custom
    pull_policy: never

  celery:
    build:
      context: ./customgateway/
      dockerfile: Dockerfile-celery
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_celery_custom
    pull_policy: never

  celerybeat:
    build:
      context: ./customgateway/
      dockerfile: Dockerfile-celerybeat
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_celerybeat_custom
    pull_policy: never

  operations:
    build:
      context: ./customgateway/
      dockerfile: Dockerfile-operations
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_operations_custom
    pull_policy: never

At this point, you should have the following directory structure:

compose
├── customgateway
│         ├── Dockerfile-backend
│         ├── Dockerfile-celery
│         ├── Dockerfile-celerybeat
│         ├── Dockerfile-operations
│         ├── Dockerfile-updated
│         └── gateway-template
│             ├── README.md
│             └── newgateway
│                 ├── __init__.py
│                 ├── apps.py
│                 ├── conf.py
│                 ├── models.py
│                 └── newgateway.py
├── docker-compose.override.yml
├── docker-compose.yml
├── env_template
└── secrets

If everything looks ok, you can build your new image and make sure that the affected containers are being reloaded and they’re using thew new custom build images:

cd /home/fleio/compose
docker compose build && docker compose up -d

Run docker ps -a command to confirm that the rebuild containers reloaded (uptime should be a few seconds) and they’re using the fleio custom images:

CONTAINER ID   IMAGE                                        COMMAND                  CREATED          STATUS          PORTS                                                             NAMES
c52140d9f894   hub.fleio.com/fleio_web-2023-02:1            "/docker-entrypoint.…"   4 seconds ago    Up 3 seconds    80/tcp, 0.0.0.0:80->8080/tcp, :::80->8080/tcp                     fleio-web-1
fa8228540bbe   fleio_backend_custom                         "/var/webapps/fleio/…"   11 seconds ago   Up 6 seconds    8000/tcp                                                          fleio-backend-1
a227f0badff4   fleio_updated_custom                         "/var/webapps/fleio/…"   11 seconds ago   Up 6 seconds                                                                      fleio-updated-1
605eb2e6286b   fleio_celerybeat_custom                      "/var/webapps/fleio/…"   11 seconds ago   Up 6 seconds                                                                      fleio-celerybeat-1
a267943154f1   fleio_celery_custom                          "/var/webapps/fleio/…"   11 seconds ago   Up 6 seconds                                                                      fleio-celery-1
e2d260de66bf   fleio_operations_custom                      "/var/webapps/fleio/…"   11 seconds ago   Up 6 seconds                                                                      fleio-operations-1
706aeca45b84   hub.fleio.com/fleio_incomingmail-2023-02:1   "/var/webapps/fleio/…"   45 minutes ago   Up 24 minutes                                                                     fleio-incomingmail-1
f18bd6760827   hub.fleio.com/fleio_frontend-2023-02:1       "/docker-entrypoint.…"   45 minutes ago   Up 24 minutes   80/tcp                                                            fleio-frontend-1
dfea54b07fab   hub.fleio.com/fleio_fluentd-2023-02:1        "tini -- /bin/entryp…"   45 minutes ago   Up 24 minutes   5140/tcp, 127.0.0.1:24224->24224/tcp, 127.0.0.1:24224->24224/udp  fleio-fluentd-1
688fd8203263   redis:7.0.7-alpine                           "docker-entrypoint.s…"   45 minutes ago   Up 24 minutes   6379/tcp                                                          fleio-redis-1
c8dc28269128   mariadb:10.9.4-focal                         "docker-entrypoint.s…"   48 minutes ago   Up 24 minutes   3306/tcp                                                          fleio-db-1

The next step is to add the newgateway to the django installed apps. Run fleio edit settings.py and add the following line at the end of the file:

INSTALLED_APPS += ('fleio.billing.gateways.newgateway', )
NEWGATEWAY_SETTINGS = {
    'secret_key': 'whatever!@#$',
    'test_mode': True,
    'callback_url': 'https://fleio.com',
}

Save and exit and answer with “y” when asked if you want to restart Fleio. At this point, the gateway should be visible when going to the staff/billing/gateways page in the frontend dashboard panel.

Notes on files present in newgateway directory:

  • apps.py

from django.utils.translation import ugettext_lazy as _
from django.apps import AppConfig


class NewgatewayConfig(AppConfig):
    name = "fleio.billing.gateways.newgateway"
    verbose_name = _("NewGateway")
    fleio_module_type = 'payment_gateway'
    module_settings = {
        'capabilities': {
            'can_process_payments': True,
            'returns_fee_information': False
        }
    }

The returns_fee_information attribute from module_settings specifies if this gateway returns fee information. If so, fees will automatically be added to transactions otherwise they may be added from frontend on the /staff/billing/gateways page.

  • conf.py

from django.conf import settings


class Conf(object):
    def __init__(self):
        self.newgateway_settings = getattr(settings, 'NEWGATEWAY_SETTINGS', {})
        self.test_mode = self.newgateway_settings.get('test_mode')
        self.secret_key = self.newgateway_settings.get('secret_key')
        self.callback_url = self.newgateway_settings.get('callback_url')

conf = Conf()

As you can see, the first line in the __init__(self) method gets the gateway settings dictionary from the settings.py file. You defined a dictionary in settings.py earlier, containing all the information and variables required by your gateway.

The lines just retrieve each value from the dictionary and assigns them to variables defined on the Conf class.

The dictionary defined in settings.py may look like this given the above example:

NEWGATEWAY_SETTINGS = {
    'secret_key': 'whatever!@#$',
    'test_mode': True,
    'callback_url': 'https://fleio.com',
}
  • newgateway.py

from django.conf import settings
from django.http import HttpResponseRedirect

from .conf import conf

from fleio.billing.gateways.decorators import gateway_action, staff_gateway_action
from fleio.billing.gateways import exceptions as gateway_exceptions

from fleio.core.utils import fleio_join_url


def process_test_payment(test_mode):
    pass


@gateway_action(methods=['GET'])
def pay_invoice(request):
    invoice_id = request.query_params.get('invoice')

    try:
        process_test_payment(test_mode=conf.test_mode)
    except Exception as create_payment_exception:
        # handle possible exception
        raise gateway_exceptions.InvoicePaymentException(
            message=str(create_payment_exception),
            invoice_id=invoice_id
        )
    # redirect to invoice
    relative_url = 'billing/invoices/{}'.format(invoice_id)

Note on 4th line (from fleio.billing.gateways.decorators import gateway_action, staff_gateway_action):

These decorators are used for functions that can be done by end-users or staff users. There is also the callback(request) function. This will be used in case you want to implement callbacks from the gateway (see the example from stripe.py file).

An example of pay_invoice function can be this:

from django.conf import settings
from django.http import HttpResponseRedirect

from .conf import conf

from fleio.billing.gateways.decorators import gateway_action, staff_gateway_action
from fleio.billing.gateways import exceptions as gateway_exceptions

from fleio.core.utils import fleio_join_url


def process_test_payment(test_mode):
    pass


@gateway_action(methods=['GET'])
def pay_invoice(request):
    invoice_id = request.query_params.get('invoice')

    try:
        process_test_payment(test_mode=conf.test_mode)
    except Exception as create_payment_exception:
        # handle possible exception
        raise gateway_exceptions.InvoicePaymentException(
            message=str(create_payment_exception),
            invoice_id=invoice_id
        )
    # redirect to invoice (or maybe render a gateway template)
    relative_url = 'billing/invoices/{}'.format(invoice_id)
    return HttpResponseRedirect(fleio_join_url(settings.FRONTEND_URL, relative_url))

You will now see that when paying an invoice this code gets executed.

Other decorated methods you can use:

  • Using the gateway_action decorator: pay_invoice, confirm_payment, cancel_payment,

  • Using the staff_gateway_action decorator: refund, capture

For rendering custom html pages you may find inspiration in the existing Stripe or Romcard gateways.