forked from GithubBackups/healthchecks
Pricing updates.
This commit is contained in:
parent
ba6995198b
commit
01fef3d054
20
hc/payments/migrations/0005_subscription_plan_name.py
Normal file
20
hc/payments/migrations/0005_subscription_plan_name.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2018-03-04 17:28
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('payments', '0004_subscription_send_invoices'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='subscription',
|
||||
name='plan_name',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
]
|
@ -42,35 +42,12 @@ class Subscription(models.Model):
|
||||
payment_method_token = models.CharField(max_length=35, blank=True)
|
||||
subscription_id = models.CharField(max_length=10, blank=True)
|
||||
plan_id = models.CharField(max_length=10, blank=True)
|
||||
plan_name = models.CharField(max_length=50, blank=True)
|
||||
address_id = models.CharField(max_length=2, blank=True)
|
||||
send_invoices = models.BooleanField(default=True)
|
||||
|
||||
objects = SubscriptionManager()
|
||||
|
||||
def price(self):
|
||||
if self.plan_id == "P5":
|
||||
return 5
|
||||
elif self.plan_id == "P50":
|
||||
return 50
|
||||
elif self.plan_id == "Y48":
|
||||
return 48
|
||||
elif self.plan_id == "Y480":
|
||||
return 480
|
||||
elif self.plan_id == "T144":
|
||||
return 144
|
||||
|
||||
return 0
|
||||
|
||||
def period(self):
|
||||
if self.plan_id.startswith("P"):
|
||||
return "month"
|
||||
elif self.plan_id.startswith("Y"):
|
||||
return "year"
|
||||
elif self.plan_id.startswith("T"):
|
||||
return "3 years"
|
||||
|
||||
raise NotImplementedError("Unexpected plan: %s" % self.plan_id)
|
||||
|
||||
@property
|
||||
def payment_method(self):
|
||||
if not self.payment_method_token:
|
||||
@ -160,6 +137,15 @@ class Subscription(models.Model):
|
||||
if result.is_success:
|
||||
self.subscription_id = result.subscription.id
|
||||
self.plan_id = plan_id
|
||||
if plan_id == "P20":
|
||||
self.plan_name = "Standard ($20 / month)"
|
||||
elif plan_id == "Y192":
|
||||
self.plan_name = "Standard ($192 / year)"
|
||||
elif plan_id == "P80":
|
||||
self.plan_name = "Plus ($80 / month)"
|
||||
elif plan_id == "Y768":
|
||||
self.plan_name = "Plus ($768 / year)"
|
||||
|
||||
self.save()
|
||||
|
||||
return result
|
||||
|
@ -8,7 +8,7 @@ class PricingTestCase(BaseTestCase):
|
||||
|
||||
def test_anonymous(self):
|
||||
r = self.client.get("/pricing/")
|
||||
self.assertContains(r, "Unlimited Checks", status_code=200)
|
||||
self.assertContains(r, "Unlimited Team Members", status_code=200)
|
||||
|
||||
# A subscription object should have NOT been created
|
||||
assert Subscription.objects.count() == 0
|
||||
@ -17,7 +17,7 @@ class PricingTestCase(BaseTestCase):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
r = self.client.get("/pricing/")
|
||||
self.assertContains(r, "Unlimited Checks", status_code=200)
|
||||
self.assertContains(r, "Unlimited Team Members", status_code=200)
|
||||
|
||||
# A subscription object still should have NOT been created
|
||||
assert Subscription.objects.count() == 0
|
||||
@ -39,10 +39,11 @@ class PricingTestCase(BaseTestCase):
|
||||
def test_it_shows_active_plan(self):
|
||||
self.sub = Subscription(user=self.alice)
|
||||
self.sub.subscription_id = "test-id"
|
||||
self.sub.plan_id = "P5"
|
||||
self.sub.plan_id = "P20"
|
||||
self.sub.plan_name = "Standard ($20 / month)"
|
||||
self.sub.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
r = self.client.get("/pricing/")
|
||||
self.assertContains(r, "Standard (monthly)", status_code=200)
|
||||
self.assertContains(r, "Standard ($20 / month)", status_code=200)
|
||||
|
@ -12,7 +12,7 @@ class SetPlanTestCase(BaseTestCase):
|
||||
mock.Subscription.create.return_value.is_success = True
|
||||
mock.Subscription.create.return_value.subscription.id = "t-sub-id"
|
||||
|
||||
def run_set_plan(self, plan_id="P5"):
|
||||
def run_set_plan(self, plan_id="P20"):
|
||||
form = {"plan_id": plan_id}
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
return self.client.post("/pricing/set_plan/", form, follow=True)
|
||||
@ -31,12 +31,13 @@ class SetPlanTestCase(BaseTestCase):
|
||||
# Subscription should be filled out:
|
||||
sub = Subscription.objects.get(user=self.alice)
|
||||
self.assertEqual(sub.subscription_id, "t-sub-id")
|
||||
self.assertEqual(sub.plan_id, "P5")
|
||||
self.assertEqual(sub.plan_id, "P20")
|
||||
self.assertEqual(sub.plan_name, "Standard ($20 / month)")
|
||||
|
||||
# User's profile should have a higher limits
|
||||
self.profile.refresh_from_db()
|
||||
self.assertEqual(self.profile.ping_log_limit, 1000)
|
||||
self.assertEqual(self.profile.check_limit, 500)
|
||||
self.assertEqual(self.profile.check_limit, 50)
|
||||
self.assertEqual(self.profile.team_limit, 9)
|
||||
self.assertEqual(self.profile.sms_limit, 50)
|
||||
self.assertEqual(self.profile.sms_sent, 0)
|
||||
@ -52,20 +53,49 @@ class SetPlanTestCase(BaseTestCase):
|
||||
self.profile.sms_sent = 1
|
||||
self.profile.save()
|
||||
|
||||
r = self.run_set_plan("Y48")
|
||||
r = self.run_set_plan("Y192")
|
||||
self.assertRedirects(r, "/accounts/profile/billing/")
|
||||
|
||||
# Subscription should be filled out:
|
||||
sub = Subscription.objects.get(user=self.alice)
|
||||
self.assertEqual(sub.subscription_id, "t-sub-id")
|
||||
self.assertEqual(sub.plan_id, "Y48")
|
||||
self.assertEqual(sub.plan_id, "Y192")
|
||||
self.assertEqual(sub.plan_name, "Standard ($192 / year)")
|
||||
|
||||
# User's profile should have a higher limits
|
||||
self.profile.refresh_from_db()
|
||||
self.assertEqual(self.profile.ping_log_limit, 1000)
|
||||
self.assertEqual(self.profile.check_limit, 50)
|
||||
self.assertEqual(self.profile.team_limit, 9)
|
||||
self.assertEqual(self.profile.sms_limit, 50)
|
||||
self.assertEqual(self.profile.sms_sent, 0)
|
||||
|
||||
# braintree.Subscription.cancel should have not been called
|
||||
assert not mock.Subscription.cancel.called
|
||||
|
||||
@patch("hc.payments.models.braintree")
|
||||
def test_plus_works(self, mock):
|
||||
self._setup_mock(mock)
|
||||
|
||||
self.profile.sms_limit = 0
|
||||
self.profile.sms_sent = 1
|
||||
self.profile.save()
|
||||
|
||||
r = self.run_set_plan("P80")
|
||||
self.assertRedirects(r, "/accounts/profile/billing/")
|
||||
|
||||
# Subscription should be filled out:
|
||||
sub = Subscription.objects.get(user=self.alice)
|
||||
self.assertEqual(sub.subscription_id, "t-sub-id")
|
||||
self.assertEqual(sub.plan_id, "P80")
|
||||
self.assertEqual(sub.plan_name, "Plus ($80 / month)")
|
||||
|
||||
# User's profile should have a higher limits
|
||||
self.profile.refresh_from_db()
|
||||
self.assertEqual(self.profile.ping_log_limit, 1000)
|
||||
self.assertEqual(self.profile.check_limit, 500)
|
||||
self.assertEqual(self.profile.team_limit, 9)
|
||||
self.assertEqual(self.profile.sms_limit, 50)
|
||||
self.assertEqual(self.profile.team_limit, 500)
|
||||
self.assertEqual(self.profile.sms_limit, 500)
|
||||
self.assertEqual(self.profile.sms_sent, 0)
|
||||
|
||||
# braintree.Subscription.cancel should have not been called
|
||||
@ -77,7 +107,7 @@ class SetPlanTestCase(BaseTestCase):
|
||||
|
||||
self.sub = Subscription(user=self.alice)
|
||||
self.sub.subscription_id = "test-id"
|
||||
self.sub.plan_id = "P5"
|
||||
self.sub.plan_id = "P20"
|
||||
self.sub.save()
|
||||
|
||||
self.profile.sms_limit = 1
|
||||
|
@ -93,7 +93,7 @@ def log_and_bail(request, result):
|
||||
@require_POST
|
||||
def set_plan(request):
|
||||
plan_id = request.POST["plan_id"]
|
||||
if plan_id not in ("", "P5", "P50", "Y48", "Y480", "T144"):
|
||||
if plan_id not in ("", "P20", "P80", "Y192", "Y768"):
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
sub = Subscription.objects.for_user(request.user)
|
||||
@ -117,14 +117,14 @@ def set_plan(request):
|
||||
|
||||
# Update user's profile
|
||||
profile = request.user.profile
|
||||
if plan_id in ("P5", "Y48", "T144"):
|
||||
if plan_id in ("P20", "Y192"):
|
||||
profile.ping_log_limit = 1000
|
||||
profile.check_limit = 500
|
||||
profile.check_limit = 50
|
||||
profile.team_limit = 9
|
||||
profile.sms_limit = 50
|
||||
profile.sms_sent = 0
|
||||
profile.save()
|
||||
elif plan_id in ("P50", "Y480"):
|
||||
elif plan_id in ("P80", "Y768"):
|
||||
profile.ping_log_limit = 1000
|
||||
profile.check_limit = 500
|
||||
profile.team_limit = 500
|
||||
|
@ -36,4 +36,13 @@ span.loading {
|
||||
|
||||
.billing-empty {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.at-limit span {
|
||||
display: inline-block;
|
||||
background-color: #FFD54F;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
border-radius: 2px;
|
||||
padding: 2px 6px;
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
$(function () {
|
||||
$("#period-controls :input").change(function() {
|
||||
if (this.value == "monthly") {
|
||||
$("#s-price").text("$5");
|
||||
$("#p-price").text("$50");
|
||||
$("#s-price").text("$20");
|
||||
$("#p-price").text("$80");
|
||||
}
|
||||
|
||||
if (this.value == "annual") {
|
||||
$("#s-price").text("$4");
|
||||
$("#p-price").text("$40");
|
||||
$("#s-price").text("$16");
|
||||
$("#p-price").text("$64");
|
||||
}
|
||||
});
|
||||
});
|
@ -46,13 +46,7 @@
|
||||
{% if sub is None or sub.plan_id == "" %}
|
||||
Free
|
||||
{% else %}
|
||||
{% if sub.plan_id == "P5" or sub.plan_id == "Y48" or sub.plan_id == "T144" %}
|
||||
Standard
|
||||
{% elif sub.plan_id == "P50" or sub.plan_id == "Y480" %}
|
||||
Plus
|
||||
{% endif %}
|
||||
|
||||
(${{ sub.price }} per {{ sub.period }})
|
||||
{{ sub.plan_name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
@ -66,24 +60,21 @@
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>Checks Used</td>
|
||||
<td>
|
||||
{{ num_checks }} of
|
||||
{% if sub.plan_id %}
|
||||
unlimited
|
||||
{% else %}
|
||||
{{ profile.check_limit }}
|
||||
{% endif %}
|
||||
<td {% if num_checks >= profile.check_limit %} class="at-limit" {% endif %}>
|
||||
<span>{{ num_checks }} of {{ profile.check_limit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Team Size</td>
|
||||
<td>
|
||||
<td {% if team_size >= profile.team_limit %} class="at-limit" {% endif %}>
|
||||
<span>
|
||||
{{ team_size }} of
|
||||
{% if profile.team_limit == 500 %}
|
||||
unlimited
|
||||
{% else %}
|
||||
{{ team_max }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -219,57 +210,46 @@
|
||||
Enjoy free service.
|
||||
</label>
|
||||
|
||||
<h2>Standard <small>Unlimited checks, 20 team members</small></h2>
|
||||
<h2>Standard <small>50 checks, 10 team members</small></h2>
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="plan_id"
|
||||
value="P5"
|
||||
{% if sub.plan_id == "P5" %} checked {% endif %}>
|
||||
value="P20"
|
||||
{% if sub.plan_id == "P20" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
Monthly, $5/month
|
||||
Monthly, $20 / month
|
||||
</label>
|
||||
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="plan_id"
|
||||
value="Y48"
|
||||
{% if sub.plan_id == "Y48" %} checked {% endif %}>
|
||||
value="Y192"
|
||||
{% if sub.plan_id == "Y192" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
Annual, $48/year (20% off monthly)
|
||||
Annual, $192 / year (20% off monthly)
|
||||
</label>
|
||||
|
||||
<h2>Plus <small>500 checks, unlimited team members</small></h2>
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="plan_id"
|
||||
value="P80"
|
||||
{% if sub.plan_id == "P80" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
Monthly, $80/month
|
||||
</label>
|
||||
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="plan_id"
|
||||
value="T144"
|
||||
{% if sub.plan_id == "T144" %} checked {% endif %}>
|
||||
value="Y768"
|
||||
{% if sub.plan_id == "Y768" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
3-year, $144 per 3 years (20% off monthly)
|
||||
</label>
|
||||
|
||||
|
||||
<h2>Plus <small>Unlimited checks, unlimited team members</small></h2>
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="plan_id"
|
||||
value="P50"
|
||||
{% if sub.plan_id == "P50" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
Monthly, $50/month
|
||||
</label>
|
||||
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="plan_id"
|
||||
value="Y480"
|
||||
{% if sub.plan_id == "Y480" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
Annual, $480/year (20% off monthly)
|
||||
Annual, $768/year (20% off monthly)
|
||||
</label>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
|
@ -45,7 +45,7 @@
|
||||
<div class="alert alert-info">
|
||||
<strong>Check limit reached.</strong>
|
||||
To add more checks, please
|
||||
<a href="{% url 'hc-pricing' %}">upgrade your account!</a>
|
||||
<a href="{% url 'hc-billing' %}">upgrade your account!</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -13,29 +13,21 @@
|
||||
<div class="col-md-12">
|
||||
<div id="subscription-status" class="jumbotron">
|
||||
<p>
|
||||
Your account is currently on the
|
||||
{% if sub.plan_id == "P5" %}
|
||||
<strong>Standard (monthly)</strong>
|
||||
{% elif sub.plan_id == "Y48" %}
|
||||
<strong>Standard (annual)</strong>
|
||||
{% elif sub.plan_id == "T144" %}
|
||||
<strong>Standard (3 years)</strong>
|
||||
{% elif sub.plan_id == "Y480" %}
|
||||
<strong>Plus (annual)</strong>
|
||||
{% elif sub.plan_id == "P50" %}
|
||||
<strong>Plus (monthly)</strong>
|
||||
{% else %}
|
||||
<strong>Free</strong>
|
||||
{% endif %}
|
||||
plan.
|
||||
|
||||
{% if sub.plan_id %}
|
||||
You are paying
|
||||
<strong>${{ sub.price }}</strong> / {{ sub.period }}.
|
||||
{% endif %}
|
||||
Your account is currently on the
|
||||
<strong>{{ sub.plan_name }}</strong>
|
||||
plan. Thank you for supporting {% site_name %}!
|
||||
{% else %}
|
||||
Your account is currently on the
|
||||
<strong>Free</strong> plan.
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
{% if sub.plan_id %}
|
||||
<a class="btn btn-default" href="{% url 'hc-billing' %}">Billing Details</a>
|
||||
{% else %}
|
||||
<a class="btn btn-default" href="{% url 'hc-billing' %}">Billing Details and Plan Upgrades</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -100,12 +92,12 @@
|
||||
<div class="panel-body text-center">
|
||||
<h1>Standard</h1>
|
||||
<h2>
|
||||
<span id="s-price">$5</span><span class="mo">/mo</span>
|
||||
<span id="s-price">$20</span><span class="mo">/mo</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<ul class="list-group text-center">
|
||||
<li class="list-group-item">Unlimited Checks</li>
|
||||
<li class="list-group-item">50 Checks</li>
|
||||
<li class="list-group-item">10 Team Members</li>
|
||||
<li class="list-group-item">1000 log entries per check</li>
|
||||
<li class="list-group-item">50 SMS alerts per month</li>
|
||||
@ -128,12 +120,12 @@
|
||||
<div class="panel-body text-center">
|
||||
<h1>Plus</h1>
|
||||
<h2>
|
||||
<span id="p-price">$50</span><span class="mo">/mo</span>
|
||||
<span id="p-price">$80</span><span class="mo">/mo</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<ul class="list-group text-center">
|
||||
<li class="list-group-item">Unlimited Checks</li>
|
||||
<li class="list-group-item">500 Checks</li>
|
||||
<li class="list-group-item">Unlimited Team Members</li>
|
||||
<li class="list-group-item">1000 log entries per check</li>
|
||||
<li class="list-group-item">500 SMS alerts per month</li>
|
||||
|
Loading…
x
Reference in New Issue
Block a user