Forms, widgets, template tags and examples that make Stripe + Django easier.

Overview

Overview

Zebra is a library that makes using Stripe with Django even easier.

It's made of:

  • zebra, the core library, with forms, webhook handlers, abstract models, mixins, signals, and templatetags that cover most stripe implementations.
  • marty, an example app for how to integrate zebra, that also serves as its test suite.

Pull requests are quite welcome!

Usage

Installation

  1. pip install django-zebra

  2. Edit your settings.py:

    INSTALLED_APPS += ("zebra",)
    STRIPE_SECRET = "YOUR-SECRET-API-KEY"
    STRIPE_PUBLISHABLE = "YOUR-PUBLISHABLE-API-KEY"
    # Set any optional settings (below)
    
  3. (optional) ./manage.py syncdb if you have ZEBRA_ENABLE_APP = True

  4. (optional) Add in the webhook urls:

    urlpatterns += patterns('',          
    	url(r'zebra/',   include('zebra.urls',  namespace="zebra",  app_name='zebra') ),
    )
    
  5. Enjoy easy billing.

Optional Settings:

  • ZEBRA_ENABLE_APP Defaults to False. Enables Customer, Plan, and Subscription django models, as a part of zebra.
  • ZEBRA_CUSTOMER_MODEL The app+model string for the model that implements the StripeCustomerMixin. ie "myapp.MyCustomer". If ZEBRA_ENABLE_APP is true, defaults to "zebra.Customer".
  • ZEBRA_AUTO_CREATE_STRIPE_CUSTOMERS Defaults to True. Automatically creates a stripe customer object on stripe_customer access, if one doesn't exist.

Webhooks

Zebra handles all the webhooks that stripe sends back and calls a set of signals that you can plug your app into. To use the webhooks:

Note: The initial Stripe webhook system is being deprecated. See below for a description of Zebra's support for the new system.

Zebra provides:

  • zebra_webhook_recurring_payment_failed
  • zebra_webhook_invoice_ready
  • zebra_webhook_recurring_payment_succeeded
  • zebra_webhook_subscription_trial_ending
  • zebra_webhook_subscription_final_payment_attempt_failed

All of the webhooks provide the same arguments:

  • customer - if ZEBRA_CUSTOMER_MODEL is set, returns an instance that matches the stripe_customer_id, or None. If ZEBRA_CUSTOMER_MODEL is not set, returns None.
  • full_json - the full json response, parsed with simplejson.

So, for example, to update the customer's new billing date after a successful payment, you could:

(assuming you've set ZEBRA_CUSTOMER_MODEL or are using ZEBRA_ENABLE_APP):

from zebra.signals import zebra_webhook_recurring_payment_succeeded

def update_last_invoice_date(sender, **kwargs):
	customer = kwargs.pop("customer", None)
	full_json = kwargs.pop("full_json", None)
	customer.billing_date = full_json.date
	customer.save()

zebra_webhook_recurring_payment_succeeded.connect(update_last_invoice_date)

Webhooks Update

Stripe recently updated their webhook implementation (see https://stripe.com/blog/webhooks). Zebra includes an implementation of the new system.

Zebra provides:

  • zebra_webhook_charge_succeeded
  • zebra_webhook_charge_failed
  • zebra_webhook_charge_refunded
  • zebra_webhook_charge_disputed
  • zebra_webhook_customer_created
  • zebra_webhook_customer_updated
  • zebra_webhook_customer_deleted
  • zebra_webhook_customer_subscription_created
  • zebra_webhook_customer_subscription_updated
  • zebra_webhook_customer_subscription_deleted
  • zebra_webhook_customer_subscription_trial_will_end
  • zebra_webhook_customer_discount_created
  • zebra_webhook_customer_discount_updated
  • zebra_webhook_customer_discount_deleted
  • zebra_webhook_invoice_created
  • zebra_webhook_invoice_updated
  • zebra_webhook_invoice_payment_succeeded
  • zebra_webhook_invoice_payment_failed
  • zebra_webhook_invoiceitem_created
  • zebra_webhook_invoiceitem_updated
  • zebra_webhook_invoiceitem_deleted
  • zebra_webhook_plan_created
  • zebra_webhook_plan_updated
  • zebra_webhook_plan_deleted
  • zebra_webhook_coupon_created
  • zebra_webhook_coupon_updated
  • zebra_webhook_coupon_deleted
  • zebra_webhook_transfer_created
  • zebra_webhook_transfer_failed
  • zebra_webhook_ping

Zebra also provides an easy map of all the signals as zebra.signals.WEBHOOK_MAP, which maps events (charge_succeeded) to the Zebra signal (zebra_webhook_charge_succeeded). To assign a handler to all the signals that zebra sends, for example, loop over the items in the map:

for event_key, webhook_signal in WEBHOOK_MAP.iteritems():
    webhook_signal.connect(webhook_logger)

Forms

The StripePaymentForm sets up a form with fields like the official stripe example.

In particular, the form is stripped of the name attribute for any of the credit card fields, to prevent accidental submission. Media is also provided to set up stripe.js (it assumes you have jQuery).

Use it in a view like so:

if request.method == 'POST':
    zebra_form = StripePaymentForm(request.POST)
    if zebra_form.is_valid():
    	my_profile = request.user.get_profile()
        stripe_customer = stripe.Customer.retrieve(my_profile.stripe_customer_id)
        stripe_customer.card = zebra_form.cleaned_data['stripe_token']
        stripe_customer.save()

        my_profile.last_4_digits = zebra_form.cleaned_data['last_4_digits']
        my_profile.stripe_customer_id = stripe_customer.id
        my_profile.save()

        # Do something kind for the user

else:
    zebra_form = StripePaymentForm()

Template Tags

There are a couple of template tags that take care of setting up the stripe env, and rendering a basic cc update form. Note that it's expected your StripePaymentForm is called either zebra_form or form.

To use in a template:

{% extends "base.html" %}{% load zebra_tags %}

{% block head %}{{block.super}}
	{% zebra_head_and_stripe_key %}
{% endblock %}

{% block content %}
	{% zebra_card_form %}
{% endblock %}

That's it - all the stripe tokeny goodness happens, and errors are displayed to your users.

Models and Mixins

Model and Mixin docs coming. For now, the code is pretty self-explanatory, and decently documented inline.

Other Useful Bits

Zebra comes with a manage.py command to clear out all the test customers from your account. To use it, run:

./manage.py clear_stripe_test_customers

It responds to --verbosity=[0-3].

Credits

I did not write any of stripe. It just makes me happy to use, and inspired to make better APIs for my users. For Stripe info, ask them: stripe.com

Code credits are in the AUTHORS file. Pull requests welcome!

Comments
  • This project is dead

    This project is dead

    It looks like this project is dead. I've tried to contact GoodCloud, but they have not responded to any emails / pull requests.

    I have a fork over here that has a few small updates and removed some deprecated functionality that I don't anyone is still using. If anyone is interested I can submit that to PyPi and we can make it the new "master". If anyone else has a good fork, I'm all for using that instead.

    Thoughts? GoodCloud are you there?

    opened by jarcoal 8
  • Fixed django.utils.simplejson deprecation warning

    Fixed django.utils.simplejson deprecation warning

    Fixed deprecation warning for django1.6 with try/except import json as simplejson Warning was: lib/python2.7/site-packages/zebra/views.py:5: DeprecationWarning: django.utils.simplejson is deprecated; use json instead. from django.utils import simplejson

    opened by iepathos 7
  • Update Zebra to handle Stripe's new webhooks.

    Update Zebra to handle Stripe's new webhooks.

    Stripe recently updated their webhooks[1] such that they send a webhook post for many different events[2]. I've written an implementation of these new webhooks for Zebra.

    I've maintained backwards compatibility so that anyone using the old webhook system can continue to do so until it's retired. The new webhooks view defaults to /zebra/webhooks2/.

    zebra.signals contains the new signals, and also provides a WEBHOOKS_MAP structure that maps events keys to signals. When an event arrives from Stripe, the json structure has a key in it called "type", that is now a dot-delimited name, following the 'resource'.'event' scheme. So invoice_ready is now invoice.created. The new webhooks2 endpoint first converts invoice.created to invoice_created then uses this map to lookup the correct signal:

        event_json = simplejson.loads(request.raw_post_data)
        event_key = event_json['type'].replace('.', '_')
    
        if event_key in WEBHOOK_MAP:
            WEBHOOK_MAP[event_key].send( sender=None, 
                full_json=event_json )
    

    In the app using Zebra, this map can also be used to connect webhooks:

    from zebra.signals import *
    
    def webhook_logger(sender, full_json, **kwargs):
        log.info ('STRIPE EVENT: %s DATA: \n%s' % (full_json['type'], repr(full_json)))
    
    zebra_webhook_invoice_created.connect(webhook_logger)
    # same thing
    WEBHOOK_MAP['invoice_created'].connect(webhook_logger)
    

    I'm not married to the implementation, but it seemed clean and it's working. Would love to hear your thoughts!

    --Steve

    [1] https://stripe.com/blog/webhooks [2] https://stripe.com/docs/api#event_types

    opened by sivy 5
  • Webhooks broken in Django 1.6

    Webhooks broken in Django 1.6

    Webhooks are throwing exceptions since upgrading to Django 1.6.

    According to the Django Deprecation Timeline for 1.6, The attribute HttpRequest.raw_post_data was renamed to HttpRequest.body in 1.4. The backward compatibility will be removed – HttpRequest.raw_post_data will no longer work.

    Stacktrace (most recent call last):
    
      File "django/core/handlers/base.py", line 114, in get_response
        response = wrapped_callback(request, *callback_args, **callback_kwargs)
      File "newrelic/hooks/framework_django.py", line 485, in wrapper
        return wrapped(*args, **kwargs)
      File "django/views/decorators/csrf.py", line 57, in wrapped_view
        return view_func(*args, **kwargs)
      File "zebra/views.py", line 67, in webhooks_v2
        event_json = simplejson.loads(request.raw_post_data)
    
    

    Looks like changing request.raw_post_data to request.body will fix the problem. Might need to add sniffing for older versions of Django...

    opened by erikcw 1
  • Validate webhooks are actually from stripe

    Validate webhooks are actually from stripe

    Since the events have to do with billing, what is the best way to validate the webhook?

    https://github.com/GoodCloud/django-zebra/blob/master/zebra/views.py#L59

    Would it make sense to pull the id from the event object and re-request it from stripe so it is guaranteed to be official? Then pass the event object we pulled from stripe to the signal listeners.

    opened by thenewguy 1
  • Docs Update: Round 1

    Docs Update: Round 1

    The culmination of an entire day and I've barely put a dent in it.

    Live preview at http://readthedocs.org/docs/django-zebra-doc-dev/en/latest/

    I added requirements.txt to the root of the repo but it looks like that didn't fix the build errors on RTD because it needs a Django settings module.

    I'll pull the requirements file out when I pull all the autodocs out in the next round.

    opened by leetrout 1
  • Minor improvements

    Minor improvements

    Added some friendlier end user labels, fixed css values, removed a few stray tabs.

    I've tested these changes, but since I don't use git I had to cut and paste into the web editor here (which has a few bugs of its own). In short there may be a typo lurking.

    opened by mixmastamyk 1
  • Make templatetags zebra_card_form and zebra_head_and_stripe_key work in formwizard

    Make templatetags zebra_card_form and zebra_head_and_stripe_key work in formwizard

    zebra_card_form and zebra_head_and_stripe_key need 'form' in the context. However, if a form is being used inside a formwizard, 'form' is not in the context. 'Wizard' is in the context, and 'form' is inside 'wizard.' This small patch checks for the existence of 'form' in 'wizard' and assigns zebra_form to it.

    opened by cro 0
  • Getting error when initialising django-zebra

    Getting error when initialising django-zebra

    actions done

    • pip install django-zebra
    • zebra included in INSTALLED_APPS
    • added the webhook urls
      re_path(r'zebra/', include(('zebra.urls', 'zebra'), namespace="zebra",)),
    • ZEBRA_ENABLE_APP set to True
    • then tried ./manage.py makemigrations , got error
      File "project_name/manage.py", line 11, in <module>
        execute_from_command_line(sys.argv)
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
        utility.execute()
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/django/core/management/__init__.py", line 357, in execute
        django.setup()
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/django/__init__.py", line 24, in setup
        apps.populate(settings.INSTALLED_APPS)
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/django/apps/registry.py", line 114, in populate
        app_config.import_models()
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/django/apps/config.py", line 211, in import_models
        self.models_module = import_module(models_module_name)
      File "/usr/lib/python3.7/importlib/__init__.py", line 127, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
      File "<frozen importlib._bootstrap>", line 983, in _find_and_load
      File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 728, in exec_module
      File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/zebra/models.py", line 51, in <module>
        class Subscription(DatesModelBase, StripeSubscription):
      File "/home/aditya/dev/cn/pmx_env/lib/python3.7/site-packages/zebra/models.py", line 52, in Subscription
        customer = models.ForeignKey(Customer)
    TypeError: __init__() missing 1 required positional argument: 'on_delete'```
    
    opened by aditya-cns 2
  • zebra not syncing with database on makemigrations?

    zebra not syncing with database on makemigrations?

    Using Django 1.9.4 with mezzanine 4.1.0.

    Upon installation (zebra was under INSTALLED_APPS, included URLS, had the Stripe API keys, and had ZEBRA_ENABLE_APP set to true), the necessary tables in my PostgreSQL table were not created by a normal manage.py makemigrations but I had to run makemigrations zebra in order to get this to work.

    opened by geoffrey-eisenbarth 0
Owner
GoodCloud
GoodCloud
A Django app to accept payments from various payment processors via Pluggable backends.

Django-Merchant Django-Merchant is a django application that enables you to use multiple payment processors from a single API. Gateways Following gate

Agiliq 997 Dec 24, 2022
Adyen package for django-oscar

Adyen package for django-oscar This package provides integration with the Adyen payment gateway. It is designed to work with the e-commerce framework

Oscar 13 Jan 10, 2022
PayPal integration for django-oscar. Can be used without Oscar too.

PayPal package for django-oscar This package provides integration between django-oscar and both PayPal REST API, PayPal Express (NVP) and PayPal Payfl

Oscar 146 Nov 25, 2022
A pluggable Django application for integrating PayPal Payments Standard or Payments Pro

Django PayPal Django PayPal is a pluggable application that integrates with PayPal Payments Standard and Payments Pro. See https://django-paypal.readt

Luke Plant 672 Dec 22, 2022
Django library to simplify payment processing with pin

Maintainer Wanted I no longer have any side projects that use django-pinpayments and I don't have the time or headspace to maintain an important proje

Ross Poulton 25 May 25, 2022
payu payment gateway integration for django projects

Django-PayU This package provides integration between Django and PayU Payment Gateway. Quick start Install 'django-payu' using the following command:

MicroPyramid 37 Nov 9, 2022
Drf-stripe-subscription - An out-of-box Django REST framework solution for payment and subscription management using Stripe

Drf-stripe-subscription - An out-of-box Django REST framework solution for payment and subscription management using Stripe

Oscar Y Chen 68 Jan 7, 2023
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Jan 5, 2023
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Dec 31, 2022
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Jan 7, 2023
AWS Tags As A Database is a Python library using AWS Tags as a Key-Value database.

AWS Tags As A Database is a Python library using AWS Tags as a Key-Value database. This database is completely free* ??

Oren Leung 42 Nov 25, 2022
Portfolio and E-commerce site built on Python-Django and Stripe checkout

StripeMe Introduction Stripe Me is an e-commerce and portfolio website offering communication services, including web-development, graphic design and

null 3 Jul 5, 2022
Django + Stripe Made Easy

dj-stripe Stripe Models for Django. Introduction dj-stripe implements all of the Stripe models, for Django. Set up your webhook endpoint and start rec

dj-stripe 1.3k Dec 28, 2022
A Python command-line utility for validating that the outputs of a given Declarative Form Azure Portal UI JSON template map to the input parameters of a given ARM Deployment Template JSON template

A Python command-line utility for validating that the outputs of a given Declarative Form Azure Portal UI JSON template map to the input parameters of a given ARM Deployment Template JSON template

Glenn Musa 1 Feb 3, 2022
django-quill-editor makes Quill.js easy to use on Django Forms and admin sites

django-quill-editor django-quill-editor makes Quill.js easy to use on Django Forms and admin sites No configuration required for static files! The ent

lhy 139 Dec 5, 2022
Flask-template - A simple template for make an flask api

flask-template By GaGoU :3 a simple template for make an flask api notes: you ca

GaGoU 2 Feb 17, 2022
A Program that generates and checks Stripe keys 24x7.

A Program that generates and checks Stripe keys 24x7. This was made only for Educational Purposes, I'm not responsible for the damages cause by you

iNaveen 18 Dec 17, 2022
Python library for the Stripe API.

Stripe Python Library The Stripe Python library provides convenient access to the Stripe API from applications written in the Python language. It incl

Stripe 1.3k Jan 3, 2023
This Python based program checks your CC Stripe Auth 1$ Based Checker

CC-Checker This Python based program checks your CC Stripe Auth 1$ Based Checker About Author Coded by xBlackx Reach Me On Telegram @xBlackx_Coder jOI

xBlackxCoder 11 Nov 20, 2022