================ 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 :doc:`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: .. code-block:: bash 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 .. code-block:: bash 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 .. code-block:: bash 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 .. code-block:: bash 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 .. code-block:: bash 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 .. code-block:: bash 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: .. code-block:: bash # 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 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: .. code-block:: bash 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: .. code-block:: bash 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: .. code-block:: bash 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: .. code-block:: python 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 .. code-block:: python 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 .. code-block:: python 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: .. code-block:: python NEWGATEWAY_SETTINGS = { 'secret_key': 'whatever!@#$', 'test_mode': True, 'callback_url': 'https://fleio.com', } * newgateway.py .. code-block:: python 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: .. code-block:: python 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.