diff --git a/hc/front/urls.py b/hc/front/urls.py index 2c5289b3..b9a957b9 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -11,7 +11,6 @@ urlpatterns = [ url(r'^checks/([\w-]+)/email/$', views.email_preview), url(r'^checks/([\w-]+)/remove/$', views.remove_check, name="hc-remove-check"), url(r'^checks/([\w-]+)/log/$', views.log, name="hc-log"), - url(r'^pricing/$', views.pricing, name="hc-pricing"), url(r'^docs/$', views.docs, name="hc-docs"), url(r'^about/$', views.about, name="hc-about"), url(r'^integrations/$', views.channels, name="hc-channels"), diff --git a/hc/front/views.py b/hc/front/views.py index afe89586..ecd35135 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -47,10 +47,6 @@ def index(request): return render(request, "front/welcome.html", ctx) -def pricing(request): - return render(request, "front/pricing.html", {"page": "pricing"}) - - def docs(request): if "welcome_code" in request.session: code = request.session["welcome_code"] diff --git a/hc/payments/__init__.py b/hc/payments/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hc/payments/admin.py b/hc/payments/admin.py new file mode 100644 index 00000000..67599c92 --- /dev/null +++ b/hc/payments/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from .models import Subscription + + +@admin.register(Subscription) +class SubsAdmin(admin.ModelAdmin): + + list_display = ("id", "user") diff --git a/hc/payments/context_processors.py b/hc/payments/context_processors.py new file mode 100644 index 00000000..a6a428eb --- /dev/null +++ b/hc/payments/context_processors.py @@ -0,0 +1,5 @@ +from django.conf import settings + + +def payments(request): + return {'USE_PAYMENTS': settings.USE_PAYMENTS} diff --git a/hc/payments/migrations/0001_initial.py b/hc/payments/migrations/0001_initial.py new file mode 100644 index 00000000..0f87d3de --- /dev/null +++ b/hc/payments/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Subscription', + fields=[ + ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), + ('customer_id', models.CharField(blank=True, max_length=36)), + ('payment_method_token', models.CharField(blank=True, max_length=35)), + ('subscription_id', models.CharField(blank=True, max_length=10)), + ('user', models.OneToOneField(blank=True, null=True, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/hc/payments/migrations/__init__.py b/hc/payments/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hc/payments/models.py b/hc/payments/models.py new file mode 100644 index 00000000..30045204 --- /dev/null +++ b/hc/payments/models.py @@ -0,0 +1,9 @@ +from django.contrib.auth.models import User +from django.db import models + + +class Subscription(models.Model): + user = models.OneToOneField(User, blank=True, null=True) + customer_id = models.CharField(max_length=36, blank=True) + payment_method_token = models.CharField(max_length=35, blank=True) + subscription_id = models.CharField(max_length=10, blank=True) diff --git a/hc/payments/tests.py b/hc/payments/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/hc/payments/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/hc/payments/urls.py b/hc/payments/urls.py new file mode 100644 index 00000000..500291b3 --- /dev/null +++ b/hc/payments/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^pricing/$', + views.pricing, + name="hc-pricing"), + + url(r'^create_subscription/$', + views.create, + name="hc-create-subscription"), + + url(r'^subscription_status/$', + views.status, + name="hc-subscription-status"), + +] diff --git a/hc/payments/views.py b/hc/payments/views.py new file mode 100644 index 00000000..e56f36f2 --- /dev/null +++ b/hc/payments/views.py @@ -0,0 +1,81 @@ +import braintree +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.shortcuts import redirect, render + +from .models import Subscription + + +def setup_braintree(): + kw = { + "merchant_id": settings.BRAINTREE_MERCHANT_ID, + "public_key": settings.BRAINTREE_PUBLIC_KEY, + "private_key": settings.BRAINTREE_PRIVATE_KEY + } + + braintree.Configuration.configure(settings.BRAINTREE_ENV, **kw) + + +def pricing(request): + ctx = { + "page": "pricing", + } + return render(request, "payments/pricing.html", ctx) + + +@login_required +def create(request): + setup_braintree() + + try: + sub = Subscription.objects.get(user=request.user) + except Subscription.DoesNotExist: + sub = Subscription(user=request.user) + sub.save() + + if request.method == "POST": + if not sub.customer_id: + result = braintree.Customer.create({}) + assert result.is_success + sub.customer_id = result.customer.id + sub.save() + + result = braintree.PaymentMethod.create({ + "customer_id": sub.customer_id, + "payment_method_nonce": request.POST["payment_method_nonce"] + }) + assert result.is_success + sub.payment_method_token = result.payment_method.token + sub.save() + + result = braintree.Subscription.create({ + "payment_method_token": sub.payment_method_token, + "plan_id": "pww", + "price": 5 + }) + + sub.subscription_id = result.subscription.id + sub.save() + + return redirect("hc-subscription-status") + + ctx = { + "page": "pricing", + "client_token": braintree.ClientToken.generate() + } + return render(request, "payments/create_subscription.html", ctx) + + +@login_required +def status(request): + setup_braintree() + + sub = Subscription.objects.get(user=request.user) + subscription = braintree.Subscription.find(sub.subscription_id) + + ctx = { + "page": "pricing", + "subscription": subscription + } + + return render(request, "payments/status.html", ctx) diff --git a/hc/settings.py b/hc/settings.py index 30d359b6..83abc219 100644 --- a/hc/settings.py +++ b/hc/settings.py @@ -20,6 +20,7 @@ SECRET_KEY = "---" DEBUG = True ALLOWED_HOSTS = [] DEFAULT_FROM_EMAIL = 'healthchecks@example.org' +USE_PAYMENTS = False INSTALLED_APPS = ( @@ -35,7 +36,8 @@ INSTALLED_APPS = ( 'hc.accounts', 'hc.api', - 'hc.front' + 'hc.front', + 'hc.payments' ) MIDDLEWARE_CLASSES = ( @@ -62,6 +64,7 @@ TEMPLATES = [ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', + 'hc.payments.context_processors.payments' ], }, }, diff --git a/hc/urls.py b/hc/urls.py index 5351cbea..a890f794 100644 --- a/hc/urls.py +++ b/hc/urls.py @@ -6,4 +6,5 @@ urlpatterns = [ url(r'^accounts/', include('hc.accounts.urls')), url(r'^', include('hc.api.urls')), url(r'^', include('hc.front.urls')), + url(r'^', include('hc.payments.urls')), ] diff --git a/templates/base.html b/templates/base.html index dec36838..3ce911f4 100644 --- a/templates/base.html +++ b/templates/base.html @@ -20,7 +20,9 @@ + {% if USE_PAYMENTS %} + {% endif %} @@ -80,9 +82,11 @@ {% endif %} + {% if USE_PAYMENTS %}
  • Pricing
  • + {% endif %}
  • Docs diff --git a/templates/payments/create_subscription.html b/templates/payments/create_subscription.html new file mode 100644 index 00000000..0e6065fc --- /dev/null +++ b/templates/payments/create_subscription.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} +{% load staticfiles %} + +{% block title %}Pricing - It's Free! - healthchecks.io{% endblock %} + +{% block content %} + +
    + {% csrf_token %} +
    + +
    + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/front/pricing.html b/templates/payments/pricing.html similarity index 98% rename from templates/front/pricing.html rename to templates/payments/pricing.html index 03062b26..852d3d4c 100644 --- a/templates/front/pricing.html +++ b/templates/payments/pricing.html @@ -37,5 +37,4 @@ - {% endblock %} \ No newline at end of file diff --git a/templates/payments/status.html b/templates/payments/status.html new file mode 100644 index 00000000..20171e2f --- /dev/null +++ b/templates/payments/status.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} +{% load staticfiles %} + +{% block title %}Pricing - It's Free! - healthchecks.io{% endblock %} + +{% block content %} + +

    Subscription Status

    + +
    +
    Status
    +
    {{ subscription.status }}
    + +
    Next Billing Date:
    +
    {{ subscription.next_billing_date }}
    + + +
    Amount
    +
    {{ subscription.price }} / Month
    + + +
    + +

    Transactions

    + + + + + + {% for tx in subscription.transactions %} + + + + + {% endfor %} +
    DateAmount
    ???{{ tx.amount }}
    + + +{% endblock %} \ No newline at end of file