Development
===========
.. _installation:
Installation
------------
Install the package and dependencies::
pip install -r requirements.txt
pipe install -e .
Create a ``config.json`` file::
cp config-example.json config.json
Fill out the ``STRIPE_API_KEY`` and ``VISIT_API_KEY`` settings.
Setup a local (sqlite) database::
python manage-dev.py migrate
python manage-dev.py createsuperuser
python manage-dev.py loaddata prices-test.json
This will create a file ``db.sqlite`` and initialize it with the necessary tables and data. You
can now run a development server by running::
python manage-dev.py runserver
.. _invoking-management-commands:
Invoking management commands
----------------------------
The ``manage-dev.py`` file is an entrypoint to running django management commands. The generic CLI
tool for running
`django-admin`
This command requires at least one enviroment variable to be set ``DJANGO_SETTINGS_MODULE`` to
point to a python module for the project's settings as a dotted path. For local development, the
path should be ``stripe_checkout.settings.dev``. Inside the root of the ``stripe_checkout`` repository,
The ``manage-dev.py`` file is preconfigured with this enviroment variable, and a ``CONFIG_FILENAME``
environment variable pointing to the ``config.json`` file created during :ref:`installation`.
When invoking management commands in the deployed VMs you should use the ``/home/tnc/cmd.sh``
script instead of ``django-admin``. This script is configured with the correct environment variables
for running django commands against the deployed instance.
Settings
--------
There are three ways of supplying settings. These are described below
Settings file
#############
For development, use the ``stripe_checkout.settings.dev`` settings module. Deployed environments
(test, uat, prod) use the ``stripe_checkout.settings.prod`` settings module. These files contain
settings that are static between the environments, and contain some logic for reading and parsing
environment variables that are set for specific environments.
.. _config_json:
Config file
###########
The config file is a way to supply settings that are non-static, and therefore cannot be placed
in a settings file. The config file must be a json file containing a top level dictionary, where
the keys are settings (are therefore must be ``UPPER_CASE``) and are directly interpreted as django
settings. This allows the values to have an arbitrary structure other than a single string, such
as an array. The config file is validated to a json schema, located in ``stripe_checkout.config``.
In order to use a specific config file, set the ``CONFIG_FILENAME`` environment variable to a file
path ``path/to/config.json`` that points to a valid config file. This can be an absolute path or
a relative path. For discoverability, it is better to use an absolute path.
Environment Variables
#####################
We use the ``DJANGO_SETTINGS_MODULE`` and ``CONFIG_FILENAME`` to point to the settings file
``dotted.path`` and config file ``path/to/config.json``. There are also other environment variables
for settings that cannot be static in a settings file, because they either vary between environments,
or contain sensitive information. The settings files are set up in a way to read certain enviroment
variables and use them for specific settings.
.. note::
Both the ``config.json`` and environment variables can be used for variable settings. When to use one
over the other is somewhat arbitrary, but there are guidelines. Settings that are relevant to the
application specifics should be placed in the ``config.json``, such as api keys and specific
stripe or visit ids. Also settings that have a more complex structure than a single string (such
as an array) are more easily set using a ``config.json`` Settings that have a more
infrastructure-like nature, or have to do with django internals, such as ``DJANGO_FRONTEND_URL``
or ``DJANGO_SECRET_KEY`` are supplied using environment variables. Another reason to use an
environment variable is when a value needs to be processed before being assigned to the actual
setting, as is the case with the ``DATABASE_URL`` environment variable.
Database
--------
Stripe checkout needs a database to function properly. In development this is a sqlite database.
You can also connect to the test database by setting the ``DATABASE_URL`` environment variable
(substitute the username and password with the data in Lastpass)::
export DATABASE_URL=postgres://:@test-postgres.geant.org/stripe_checkout
If you now run ``django-admin`` or ``manage-dev.py`` this will connect to the database for the
test deployment.
Email
-----
``stripe-checkout`` sends an email when it sees a succeeded payment intent that doesn't match an
``Order`` in the database, and therefore can't link it to a visitor's purchase. It uses Django's
`send_mail` functionality. Django uses the following settings:
- `EMAIL_HOST` (default: `localhost`)
- `EMAIL_PORT` (default: `25`)
It so happens postfix is configured on the ``stripe-checkout`` vm's to forward to the geant smtp
servers. So we don't need much additional configuration. We only configure the `DEFAULT_FROM_EMAIL`
setting. The recipients for these emails can be set using the ``SEND_ERROR_EMAILS_TO``
setting in the :ref:`config_json`
.. _stripe_webhook_endpoint:
Stripe webhook endpoint
-----------------------
Stripe can be configured to call a `webhook endpoint `_ for certain
Stripe events. These webhooks can be configured in the `Stripe Workbench `_.
Stripe is configured to call the ``/stripe-event-webhook/`` endpoint for ``payment_intent.succeeded``
and ``payment_intent.canceled`` webhooks (see also: :ref:`design`). There may be other events
configured as well, but these are ignored when :ref:`processing events `.
During development it is possible to register your locally running development server as an event
webhook using the `stripe cli `_ and register a
`local listener `_. After setting up stripe cli and
logging in, you can hook up the local developer server with the following command::
stripe listen --events payment_intent.succeeded,payment_intent.canceled \
--forward-to 127.0.0.1:8000/stripe-event-webhook/
Upon running this command, the stripe cli will output a stripe signing secret. This is a secret key
that stripe will use to sign the event payload so that we can be certain the events are actually
coming from Stripe. Add this secret to you ``config.json`` as the ``STRIPE_SIGNING_SECRET`` setting
and restart the development server.
``Events``\s will now be registered in the local database. Run the following command to process these
events::
python manage-dev.py processevents
.. note::
One way the ``/stripe-event-webhook`` is secured is through the signing secret. The second way
this endpoint is secured, is that only IP addresses from stripe can actually call this endpoint.
The full list of stripe webhook IP addresses can be found
`here `_. These IP addresses are placed in the
``STRIPE_WEBHOOK_ALLOWED_IPS`` setting in the ``stripe_checkout.settings.prod`` settings module.
.. _visit-redirect:
Visit redirect
--------------
The redirect to the stripe checkout server in Visit is done using a custom javascript snippet:
1. Click the final page "Complete"
2. Click "current page settings"
3. Clikc "Edit Javascript"
.. image:: _images/visit-form-redirect.png
:alt: Visit form redirect instructions
.. warning::
There is another method of adding javascript, namely in the form settings rather than the custom
page settings. These are the first settings you see when editing the form. Any javascript placed
here is activated for the whole form rather than a single page. Also, Javascript placed in the
form settings, overrides any javascript placed in page settings, so this will deactivate the
automatic redirect.
Redirect URL
############
The redirect url is stored in the Visit custom field ``bridgeserviceurl``. To edit this, login to
Visit, open the TNC 2025 event and follow these steps:
1. Click on Event
2. Click on Setup
3. Click on Custom fields
.. image:: _images/visit-bridgeserviceurl.png
:width: 700
:alt: Visit Redirect URL
For more information on custom fields, see the Visit `documentation `_