drf-saas-billing
|build-status-image| |pypi-version|
Overview
Fastest django app you'll ever user that provides paypal, stripe and cryptocurrency ( bitcoin) payment for your django drf saas app subscription and billings. supports normal, Flat rate: Good-better-best, usage billing based on https://github.com/ydaniels/drf-django-flexible-subscriptions
Requirements
- Python (2.7, 3.3, 3.4+)
- Django (1.6, 1.7, 1.8+)
- Django REST Framework (2.4, 3.0, 3.1+)
Installation
Install using pip\ …
.. code:: bash
$ pip install django-saas-billing
Setup
.. code:: python
# settings.py
INSTALLED_APPS = [
...,
'rest_framework',
'subscriptions_api',
'cryptocurrency_payment', #for crypto payments
'saas_billing'
]
SUBSCRIPTIONS_API_SUBSCRIPTIONTRANSACTION_MODEL = 'saas_billing.SubscriptionTransaction'
SAAS_BILLING_MODELS = {
'stripe': {
'plan': 'saas_billing.StripeSubscriptionPlan',
'cost': 'saas_billing.StripeSubscriptionPlanCost',
'subscription': 'saas_billing.StripeSubscription'
},
'paypal': {
'plan': 'saas_billing.PaypalSubscriptionPlan',
'cost': 'saas_billing.PaypalSubscriptionPlanCost',
'subscription': 'saas_billing.PaypalSubscription'
}
}
SAAS_BILLING_AUTH = {
'stripe': {
'PUBLISHABLE_KEY': 'Your Publishable Key',
'LIVE_KEY': 'You Live key can be test or live',
'CANCEL_URL': 'Where you want to redirect to if user cancels payment',
'SUCCESS_URL': ' Where to redirect to if subscription is successful'
},
'paypal': {
'CLIENT_ID': 'Your paypal rest client id',
'CLIENT_SECRET': 'Your paypal rest secret id',
'TOKEN': None,
'ENV': 'live|development',
'CANCEL_URL': 'Where to redirect to if subscription fails',
'SUCCESS_URL': 'Where to redirect to if subscription is successful',
'WEB_HOOK_ID': 'Your paypal rest webhook id'
}
}
CRYPTOCURRENCY_PAYMENT = {
"BITCOIN": {
"CODE": "btc",
"BACKEND": "merchant_wallet.backends.btc.BitcoinBackend",
"FEE": 0.00,
"REFRESH_PRICE_AFTER_MINUTE": 15,
"REUSE_ADDRESS": False,
"ACTIVE": True,
"MASTER_PUBLIC_KEY": 'PUT_YOUR_WALLET_MASTER_PUBLIC_KEY',
"CANCEL_UNPAID_PAYMENT_HRS": 24,
"CREATE_NEW_UNDERPAID_PAYMENT": True,
"IGNORE_UNDERPAYMENT_AMOUNT": 10,
"IGNORE_CONFIRMED_BALANCE_WITHOUT_SAVED_HASH_MINS": 20,
"BALANCE_CONFIRMATION_NUM": 1,
"ALLOW_ANONYMOUS_PAYMENT": False,
"DERIVATION_PATH": "m/0",
"ADDRESS_TYPE": "p2wpkh"
}
} DFS_DEFAULT_PLAN_COST_ID = 'Optional Put plan cost id here for new user to be automatically subscribed to this plan or subscription to be downgraded here' .. code-block:: python
path('', include('saas_billing.webhook_urls')) #Compulsory for webhook register url webhook on paypal and stripe
#create webhook url https://yourdomain.com/billing/stripe/webhook/
#https://yourdomain.com/billing/paypal/webhook/
path('api/subscriptions/', include('subscriptions_api.urls')),
path('api/', include('saas_billing.urls')),
Usage
Step 1
- Regsiter webhook urls on paypal and stripe
.. code-block:: bash
https://yourdomain/billing/stripe/webhook/ #Please use ngrok on localhost
https://yourdomain/billing/paypal/webhook/
- Register signal in apps.py for crypto payments to activate subscription when crypto payment gets paid
.. code-block:: python
#apps.py
class MyAppConfig(AppConfig):
def ready(self):
import saas_billing.signals
Step 2
.. code-block:: python
python manage.py migrate
- Create Your Plans and PlanCost from django admin
.. code-block:: python
from subscription_api.models import SubscriptionPlan, PlanCost, MONTH
free_plan = SubscriptionPlan(plan_name='Free Plan', features='{"can_perform_action": false, "token_limit": 3}', group=optional_already_created_group_obj_user_will_be_added_to)
free_plan.save()
pro_plan = SubscriptionPlan(plan_name='Pro Plan', features='{"can_perform_action": true, "token_limit": 10}', group=already_created_group_obj).save()
pro_plan.save()
PlanCost(plan=pro_plan, recurrence_unit=MONTH, cost=30, min_subscription_quantity=20).save() #30$/month #min_subscription_quantity user must subscribe upto quantity to use this cost
Tips
.. code-block:: python
#In your code or views you can use
if not user.subscription.plan.can_perform_action:
print('I am a free user')
else:
print('I am a pro user')
# features is a json dict that can be accessed from plan and group is normal django group that user will belong to
# You should be able to implement most subscriptions access and permissions with the feautures and django groups
Step 3
- Generate Paypal and Stripe Plans and Pricing by using command below
.. code-block:: python
python manage.py billing gateway all # Create all plans on stripe.com and paypal.com python manage.py billing gateway <paypal|stripe> # Create only on paypal.com or Stripe.com python manage.py billing gateway <paypal|stripe> --action <activate|deactivate> # Activate or Deactivate plans
Tips
Getting Active Subscriptions Of a User
.. code-block:: python
subscription = request.user.subscriptions.filter(active=True).first() #if you only allow a subscription per user
subscription.transactions.all() #returns all transaction payment of this subscriptions
request.user.subscriptions.filter(active=True).all() #for all subscriptions if you allow multiple subscription per user
.. code-block:: python
transactions = request.user.subscription_transactions.all() #Returns all payment trasnsaction for this user
Building A Payment And Active Subscription View
.. code-block:: python
from saas_billing.models import SubscriptionTransaction #import this to show crypto payments
from subscriptions_api.base_models import BaseSubscriptionTransaction # use this to only show paypal & stripe payment
class BillingView(ListView):
model = BaseSubscriptionTransaction
context_object_name = 'payment_transactions'
template_name = 'transactions.html'
def get_queryset(self):
return self.request.user.subscription_transactions.order_by('-date_transaction')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['active_subscription'] = self.request.user.subscriptions.filter(active=True).first()
return context
.. code-block:: html
<!-- transactions.html -->
<table class="table table-bordernone display" id="basic-1">
<thead>
<tr>
<th scope="col">Date</th>
<th scope="col">Subscription</th>
<th scope="col">Amount</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
{% for tran in payment_transactions %}
<tr>
<td>{{ tran.payment_transactions }}</td>
<td>
<div class="product-name">{{ tran.subscription_name }}
</div>
</td>
<td>${{ tran.amount }}</td>
<td>Paid</td>
</tr>
{% endfor %}
</tbody>
</table>
Step 4
How To Subscribe A User to a Plan Cost
-Send a post request using ajax or axios with data { gateway: <stripe|paypal|bitcoin>, quantity: 1 } to url below where ${id} is the plan cost id under subscriptions plans and quantity is optional for usage pricing
.. code-block:: javascript // post data { gateway: <stripe|paypal|bitcoin>, quantity: 1 } quantity allows use to use usage biling '/api/plan-costs/${id}/init_gateway_subscription/'
-
For paypal redirect user to payment_link value from returned data .. code-block:: javascript
$.ajax({url: '/api/plan-costs/${id-of-cost}/init_gateway_subscription/', { gateway: 'paypal', quantity: 1 }}).then((post_return_data) => { window.open(post_return_data.payment_link, '_blank').focus(); })
-
For stripe start session with session id returned from post requsest using stripe javascript sdk
.. code-block:: javascript
(post_return_data) => { var stripe = window.Stripe(YOUR_STRIPE_PUBLIC_KEY) return stripe.redirectToCheckout({ sessionId: post_return_data.session_id }) }
Thats all you need to start accepting subscriptions, subscriptions are activated or deactivated automatically and notification are sent to users automatically
Tips Api URL To use in frontend app for drf users
.. code-block:: python
'/api/subscriptions/subscription-plans/' #Get all plans to display in frontend
'/api/subscriptions/get_active_subscription/' # Returns active UserSubscription Object for the current logged in user
'/api/subscriptions/${id}/unsubscribe_user/' # Unsubscribe user from subscription with ${id}
'/api/transactions/' # Get payment transactions
'/api/transactions/${id}/' # Get single payment transaction with ${id}
Testing
Install testing requirements.
.. code:: bash
$ pip install -r requirements.txt
Run with runtests.
.. code:: bash
$ ./runtests.py
You can also use the excellent tox_ testing tool to run the tests
against all supported versions of Python and Django. Install tox
globally, and then simply run:
.. code:: bash
$ tox
Documentation
To build the documentation, you’ll need to install mkdocs.
.. code:: bash
$ pip install mkdocs
To preview the documentation:
.. code:: bash
$ mkdocs serve
Running at: http://127.0.0.1:8000/
To build the documentation:
.. code:: bash
$ mkdocs build
.. _tox: http://tox.readthedocs.org/en/latest/
.. |build-status-image| image:: https://secure.travis-ci.org/ydaniels/drf-saas-billing.svg?branch=master :target: http://travis-ci.org/ydaniels/drf-saas-billing?branch=master .. |pypi-version| image:: https://img.shields.io/pypi/v/drf-saas-billing.svg :target: https://pypi.python.org/pypi/drf-saas-billing