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
