Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nwolff committed Aug 4, 2019
0 parents commit b7a23c2
Show file tree
Hide file tree
Showing 49 changed files with 3,975 additions and 0 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
layout python3
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Python
.direnv
*.pyc
__pycache__
*.egg-info
/dist/
/build/
.tox
.coverage
.cache
test.db
.mypy_cache
.pytest_cache/

# Intellij idea
.idea
*.iml

35 changes: 35 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
dist: xenial

sudo: false

language: python

python:
- 3.6
- 3.7

install: pip install tox-travis coveralls

script: tox

stages:
- test
- name: deploy
if: tag IS present

jobs:
include:
- stage: deploy
install: skip
script: skip
deploy:
provider: pypi
user: skioo
password:
secure: "bMMhRbHn4ZPdoGAuMoHIZdpt0Op73IKc1bi0xo6kHONJXbGFli2xJXYZNz9DjiqKn2WzvQkkxnjv4yMH1jdda01XlIdqKJPxlxzEYvInMBbrbKWv7mktbneJVDYw9cX9NcXkT0sFqH8r2htoVksBg0q4nQFp2fxjELDRYmdA3QjjTEVX8nw/eNElc8sSCdC5HmVaIpPN7yIrLO3Qe+f0RFEgkV8nTvrDQ3Nsg+SbQPWf78iBj7+3+8c6HvhKvDX+Wc01NCZSsM7NPtNqpv3907SGN56mPGVdCmW7aTLNWyf3zZeD2w5TRVNoUehcx7mMahJbCW0rBSAECVHVXUGJm35cbSk4OP5NPqJNCxlEQcfoqrEpvUayyLBsVK5cAjWS0k6A2l/TqXOzJ8UPIR/94aiD6X4FKxydFhhXf1ywevyi71mz/H2nESc18sOUgmPjjCrKAIxv/7phEYJ2FPB53Tg8zWQoLfB1ixu3kh/LoZmbmhnk27NfosXflnEsii/E1pSQ+QSnyDH4SvKeQCrSbmZvIc1MWoTCdMmtizew9MgzHbI/aG7TbttOzHjYYGG+iBMZTr0yMf+M/bej3sDglK7GJksJjYurpmR86B2f/s4gKdXFZ2Dl3/xmgLpHE/O/RYVWXqbv+1zuVtSQ9TZSHTW8HDVDb3ab56Jv6HoRb60="
distribution: sdist bdist_wheel
on:
tags: true

after_success:
- coveralls
9 changes: 9 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Copyright (c) 2017, Skioo SA and individual contributors.


Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

98 changes: 98 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# django-payment

[![Build Status](https://travis-ci.org/skioo/django-payment.svg?branch=master)](https://travis-ci.org/skioo/django-payment)
[![PyPI version](https://badge.fury.io/py/django-payment.svg)](https://badge.fury.io/py/django-payment)
[![Requirements Status](https://requires.io/github/skioo/django-payment/requirements.svg?branch=master)](https://requires.io/github/skioo/django-payment/requirements/?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/skioo/django-payment/badge.svg?branch=master)](https://coveralls.io/github/skioo/django-payment?branch=master)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)


## Requirements
* Python: 3.6 and over
* Django: 2.1 and over


## Usage
To use django-payments in your existing django project:

Add payment to your `INSTALLED_APPS`:

INSTALLED_APPS = (
...
'payment.apps.PaymentConfig,
...
)


Run the migrations:

./manage.py migrate


Configure the CHECKOUT_PAYMENT_GATEWAYS and PAYMENT_GATEWAYS settings. See [example settings.py](example_project/settings.py)


## Payment gateways
This module provides implementations for the following payment-gateways:

### Stripe
Implemented features:
- Simple Payment (authorization and capture at once)
- Separate authorization and capture
- Refunds
- Split Payment with stripe connect
- Adding metadata to the stripe payment, for easy sorting in stripe


## The example project
The source distribution includes an example project that lets one exercise
the different gateway implementations without having to write any code.

Install the django-payment dependencies (the example project has identical dependencies):

pip install -e .

Create the database and admin user:

cd example_project
./manage.py migrate
./manage.py createsuperuser

Start the dev server:

./manage.py runserver

Then point your browser to:

http://127.0.0.1:8000/admin

Create a new payment.

Then operate on that payment with:

http://127.0.0.1:8000/payment/<payment-id>

## Development

To install all dependencies:

pip install -e .

To run unit tests:

pip install pytest-django
pytest

To lint, typecheck, test, and verify you didn't forget to create a migration:

pip install tox
tox

To install the version being developed into another django project:

pip install -e <path-to-this-directory>


## More information

* [The design of this application](docs/design.md)
41 changes: 41 additions & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Rationale
---------

The idea is to profit from the design and implementation of the payment gateways in saleor,
without pulling in the rest of saleor. Saleor wants to separate the payment part from the rest of saleor,
but they're not done yet: https://github.com/mirumee/saleor/issues/3422 . It also seems like it's not really in progress.

I last retrieved the saleor code on 2019-06-24, commit hash: 509cb4530

Changing as little as possible in the copied code so that next time I retrieve the saleor code I can easily apply the changes.


General architecture
--------------------
Client code interacts with a generic interface.
In interface.py Payment, the billing and shipping addresses are for optional fraud checking.

Payment-gateway implementors implement the

![payment with stripe sequence diagram](payment-with-stripe.png)


Manifest
--------
This package contains:
- A copy of the interfaces of sealor payments.
- A copy of the ```stripe``` and ```dummy``` saleor gateways package and tests (we're not interested in braintree or razorpay)
- A modified copy of the models (to remove references to saleor orders and to the saleor custom money)
- A modified copy of utils.py (again to remove references to saleor orders and to the saleor custom money)
- A modified copy of stripe/__init__.py (to fix a bug when we just want to authorize)


Our changes
-----------
- Don't depend on saleor orders from within our code
- Don't depend on postgres, so we replace jsonfield by textfield
(there is a database-independent jsonfield but it's not very useful and also unmaintained)
- Don't depend on the saleor homegrown money class.
- Remove use the DEFAULT_CURRENCY settings, the way it's used in the saleor code looks like a very bad idea.
- Use the django admin instead of a handcrafted UI.

Binary file added docs/payment-with-stripe.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added example_project/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions example_project/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env python
import os
import sys


if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
123 changes: 123 additions & 0 deletions example_project/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# flake8: noqa

import os
import sys


def abspath(*args):
return os.path.abspath(os.path.join(*args))


PROJECT_ROOT = abspath(os.path.dirname(__file__))
PAYMENT_MODULE_PATH = abspath(PROJECT_ROOT, '..')
sys.path.insert(0, PAYMENT_MODULE_PATH)

DEBUG = True

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test.db'
},
}

SECRET_KEY = 'not_so_secret'

USE_TZ = True

# Use a fast hasher to speed up tests.
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.contenttypes',
'django.contrib.staticfiles',
'django_fsm',
'djmoney',
'tests',
'payment.apps.PaymentConfig',
]

MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
]

STATIC_URL = '/static/'

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static/')

STATICFILES_DIRS = [os.path.join(PROJECT_ROOT, 'project/static')]

MEDIA_URL = '/media/'

ROOT_URLCONF = 'urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.contrib.messages.context_processors.messages',
],
},
},
]

# Enable specific currencies (djmoney)
CURRENCIES = ['USD', 'EUR', 'JPY', 'GBP', 'CAD', 'CHF']


DUMMY = "dummy"
STRIPE = "stripe"

CHECKOUT_PAYMENT_GATEWAYS = {
DUMMY: "Dummy gateway",
STRIPE: "Stripe",
}

PAYMENT_GATEWAYS = {
DUMMY: {
"module": "payment.gateways.dummy",
"config": {
"auto_capture": True,
"connection_params": {},
"template_path": "payment/dummy.html",
},
},
STRIPE: {
"module": "payment.gateways.stripe",
"config": {
"auto_capture": True,
"template_path": "payment/stripe.html",
"connection_params": {
"public_key": os.environ.get("STRIPE_PUBLIC_KEY"),
"secret_key": os.environ.get("STRIPE_SECRET_KEY"),
"store_name": os.environ.get("STRIPE_STORE_NAME", "skioo shop"),
"store_image": os.environ.get("STRIPE_STORE_IMAGE", None),
"prefill": os.environ.get("STRIPE_PREFILL", True),
"remember_me": os.environ.get("STRIPE_REMEMBER_ME", False),
"locale": os.environ.get("STRIPE_LOCALE", "auto"),
"enable_billing_address": os.environ.get(
"STRIPE_ENABLE_BILLING_ADDRESS", False
),
"enable_shipping_address": os.environ.get(
"STRIPE_ENABLE_SHIPPING_ADDRESS", False
),
},
},
},
}
20 changes: 20 additions & 0 deletions example_project/templates/operation_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<H3>Payment</H3>
<ul>
<li>gateway: {{ payment.gateway }}</li>
<li>id: {{ payment.id }}</li>
<li>total: {{ payment.total }}</li>
<li>charge_status: {{ payment.charge_status }}</li>
<li>authorized amount: {{ payment.get_authorized_amount }}</li>
<li>captured amount: {{ payment.captured_amount }}</li>
</ul>

<a href="{% url 'admin:payment_payment_change' payment.id %}">See payment in admin </a>

<H3>Stripe Operations</H3>
<ul>
<li><a href="{% url 'stripe_checkout' payment.id %}">Authorize - Checkout</a></li>
<li><a href="{% url 'stripe_elements_token' payment.id %}">Authorize - Elements token</a></li>
<li><a href="{% url 'stripe_payment_intents_manual_flow' payment.id %}">Authorize - Payment intents manual flow</a></li>
<li><a href="{% url 'stripe_capture' payment.id %}">Capture</a></li>
</ul>

25 changes: 25 additions & 0 deletions example_project/templates/stripe/checkout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<html>

<body>

<H3>Redirecting to stripe checkout</H3>


<script src="https://js.stripe.com/v3/"></script>

<script>

var stripe = Stripe('pk_test_ZVhesIICeGAEzZCbIs0U2BC6');

stripe.redirectToCheckout({
sessionId: '{{CHECKOUT_SESSION_ID}}'
}).then(function (result) {
// Failure handler
alert(result.error.message);
});

</script>

</body>

</html>

0 comments on commit b7a23c2

Please sign in to comment.