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 it’s 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 bellow:

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 it’s 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)

version: "3.7"

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

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

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

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

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

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.utils.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-2022-03: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-2022-03:1   "/var/webapps/fleio/…"   45 minutes ago   Up 24 minutes                                                   fleio_incomingmail_1
f18bd6760827   hub.fleio.com/fleio_frontend-2022-03:1       "/docker-entrypoint.…"   45 minutes ago   Up 24 minutes   80/tcp                                          fleio_frontend_1
688fd8203263   redis:6.2.6-alpine                           "docker-entrypoint.s…"   45 minutes ago   Up 24 minutes   6379/tcp                                        fleio_redis_1
c8dc28269128   mariadb:10.7.1-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.