Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
stripe-checkout
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
geant-swd
stripe-checkout
Commits
2124152a
Commit
2124152a
authored
5 months ago
by
Pelle Koster
Browse files
Options
Downloads
Patches
Plain Diff
cleanup readme and link to sphinx documentation
parent
a7386def
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
README.md
+1
-211
1 addition, 211 deletions
README.md
with
1 addition
and
211 deletions
README.md
+
1
−
211
View file @
2124152a
...
...
@@ -15,214 +15,4 @@ service acts as an in-between layer and does support these features
When visitors are registering to TNC2025 in Visit cloud, they are redirected to this service in the
final step
See the full documentation on
# Design
The design of the stripe-checkout service is roughly as following:
*
Whenever a visitor registers for TNC, they fill out a form in Visit. This form sets their
`registrationType`
. While filling out the form, the visitor may also want to purchase some extras,
such as access to side meetings or social events. The information for extras is stored in the
visitors profile as answers to certain questions. For example, there is a question for "Side
meetings" with answers "Friday" and "Sunday"
*
As the final page in the registration form, the visitor is redirected to the stripe checkout
service. Here they see what they've checked out and how much they need to pay.
*
The checkout service reads the visitor's profile through the Visit API (the visitor is
identified by their visitor id in the url).
*
From the visitor's profile, the Stripe products that the visitor needs to pay for are
determined. A visitor can have a single Registration Type item and multiple extras. Every
category of extras has two questions: One that the visitor answers with the extras they want,
and one that is goverened by the stripe checkout service when the visitor's payment has been
processed. Every answer in the paid-questions represents an extra that the visitor has paid for
These are defined as `PricedItem` objects in the database. See also:
[Adding new products or price information to the database](#adding-new-products-or-price-information-to-the-database)
below.
*
All items that the visitor has not previously purchased (see
`Order`
below) are added to a
`ShoppingCart`
and this collection is shown to the user in their checkout page
*
In their checkout page, the visitor can add some additional information that will be shown on
the invoice. These are a Purchase Order (PO) number and/or a VAT id. These fields are optional.
Then the visitor clicks Confirm to finalize the purchase
*
The stripe checkout service now creates an invoice in Stripe for the items that they need to pay
for:
*
All
`PricedItem`
objects that the visitor needs to pay for are collected in an
`Order`
and
stored in the database. Any items for which the visitor already has an
`Order`
are excluded from
the new
`Order`
, so that the visitor is charged only once for an item.
*
The visitor's billing address is read from their Visit profile.
`contact.addresses`
should
contain an address object of
`"type": "billing"`
.
**
In order for any billing information to be
shown in the Invoice, it is required that the
`country`
field is set to a valid country code in
the billing address.
**
*
The visitor is identified in stripe by their email address. If the visitor's email address
is already bound to a customer in Stripe, we use that customer, but update the billing details
using their Visit profile
*
Additional fields are added to the the invoice as
`custom_fields`
. These are:
*
Purchase Order (if any)
*
VAT number (if any)
*
GBP VAT (The VAT amount in GBP. The exchange rate read from the database and is periodically
updated by management command
`getexchangerate`
)
*
We tell Stripe to finalize and send the invoice by email to the visitor. Stripe also generates
a url where the visitor can directly pay their invoice. We redirect the user to this url. The
visitor facing part of the stripe checkout service is now finished.
*
When creating and finalizing the Invoice, Stripe also creates a payment intent. Before
redirecting the visitor to their Stripe payment page, we store the payment intent's id
(starting with
`pi_`
) along with the
`Order`
so that we can reference it later.
*
We now wait for the visitor to pay. The visitor may pay by credit card or by bank transfer. While
credit card payments are processed almost instantly, bank transfers may take time to be
processed. First, the visitor needs to actually pay, and then Stripe needs to process the
payment. The total time between placing the order and strip processing the payment may take weeks
or longer.
*
When the visitor's payment has been succesfully processed by Stripe, Stripe calls our webhook at
the
`stripe-event-webhook/`
endpoint. This endpoint does not process the event, but merely stores
it in the database as an Event. Stripe requires that this endpoint returns quickly so processing
the events happens asynchronously by periodically running the django managemement command
`processevents`
*
The
`processevents`
command looks in the database for Events that are has not processed yet. It
looks at two types of events:
`payment_intent.succeeded`
and
`payment_intent.canceled`
.
*
`payment_intent.succeeded`
events indicate that the visitor has paid. We look in the
`Order`
table for a matching Order, and update the visitor's Profile in Visit. We add the
`PAID`
tag
to the visitor to indicate that they've paid for their main registration, and add the relevant
answers to the "paid"-question for extra's.
# Development
## Config
This service needs configuation data in the form of a config json file. By default, django look
a file called
`config.json`
in the current directory. It is possble to override this by setting
the environment variable
`CONFIG_FILENAME`
to point to a different location. A sample config is
given in
`config-example.json`
. Make a copy named
`config.json`
and fill in the required data
such as the
`STRIPE_API_KEY`
and the
`VISIT.api-key`
variables.
## Database
Connecting to a database can be done by setting the DATABASE_URL environment variable to a valid
value:
```
export DATABASE_URL=postgresql://<username>:<password>@<host_address>/<database>
```
Altenatively, you can set up a local (sqlite) database. This can be done easily from the
root of this repository
```
python manage-dev.py migrate
```
This will create a database file 'db.sqlite' in the current directory. You can then create a
superuser account
```
python manage-dev.py createsuperuser
```
And finally you need to populate the database with price information. Sample price information
is given in the
`prices.json`
file, but this file may not be completely up to date
```
python manage-dev.py createprices --file prices.json
```
## Development server
You can then run the development server by running
```
python manage-dev.py runserver
```
## Admin interface
The django admin interface is enabled, so when running the development server you can browse to
`http://127.0.0.1:5000/admin`
to login to the admin interface using the credentials you created
using the createsuperuser (or other valid credentials if connected to an existing database). Here
you can manage administrative users, priced items and other things.
## Migrate price information to deployments
with the correct enviroment settings setup, it is possble to dump the latest price information by
running from the source database:
```
django-admin dumpdata stripe_checkout.PricedItem | json_pp > prices.json
```
To load price information into the target database, run:
```
django-admin loaddata prices.json
```
## 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.
# Administration
Administrative credentials are available in Lastpass
## Adding new products or price information to the database
Log in to the django admin console and add or update a
`PricedItem`
. There are two different kinds
of
`PricedItem`
:
`Registration Type`
and
`Extra`
`Registration Type`
items are used to link a visitor's
`registrationType.id`
to a Stripe product
id. Required fields are
*
`Stripe Product id`
: The stripe product for this item. Stripe product ids start with
`prod_`
*
`Visit registration id`
: The visit
`registrationType.id`
for this registration type. See also
"New registration types" below
`Extra`
items are
Aside from the fields described above, the following fields are required for all
`PricedItem`
objects:
*
`Name`
: a snake case name that helps with idenfication. This name is not shown to visitors
*
`Display Name`
: a user friendly name. This name is shown to visitors in their checkout page and
should match the user facing name in Visit and Stripe
*
`Kind`
: See above
## GBP Vat
# Visit
## Forms
Visitors are redirected to the stripe checkout server by custom javascript
## Stripe checkout host
The redirect stripe checkout host is defined in Visit as a Custom field. Navigate to the
Event -> Setup -> Custom fields, where you will find the
`bridgeserviceurl`
variable. Edit this
variable to point the forms to a different url in their final redirect
## New registration types
When creating a new registration type, its id can't be immediately retrieved. You first need to
create a visitor with that registration type,
## Adding a new checkout question
# Stripe
We use a number of Stripe resources that may need to be managed
*
Customers
*
Custom tax rate
*
Invoice template
*
Webhooks (+ signing secret)
## Webhooks
\ No newline at end of file
See the full documentation on
[
SWD Documentation
](
https://swd-documentation.geant.org/stripe-checkout/develop/
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment