From f1880657fde9c832b77daaa759cf42de41605a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= Date: Tue, 7 Apr 2020 12:32:20 +0300 Subject: [PATCH] Added "Supporter" billing plan. --- hc/payments/models.py | 4 + hc/payments/tests/test_update_subscription.py | 30 ++++- hc/payments/views.py | 15 ++- static/css/billing.css | 8 +- static/css/pricing.css | 76 ++++++++---- static/js/billing.js | 23 +++- static/js/pricing.js | 10 +- templates/accounts/billing.html | 30 +++-- templates/payments/pricing.html | 108 +++++++++++------- 9 files changed, 220 insertions(+), 84 deletions(-) diff --git a/hc/payments/models.py b/hc/payments/models.py index 50aa19c4..d546eec4 100644 --- a/hc/payments/models.py +++ b/hc/payments/models.py @@ -130,6 +130,10 @@ class Subscription(models.Model): self.plan_name = "Business Plus ($80 / month)" elif plan_id == "Y768": self.plan_name = "Business Plus ($768 / year)" + elif plan_id == "S5": + self.plan_name = "Supporter ($5 / month)" + elif plan_id == "S48": + self.plan_name = "Supporter ($48 / year)" self.save() diff --git a/hc/payments/tests/test_update_subscription.py b/hc/payments/tests/test_update_subscription.py index 5f20e85d..40b32cfb 100644 --- a/hc/payments/tests/test_update_subscription.py +++ b/hc/payments/tests/test_update_subscription.py @@ -48,6 +48,34 @@ class UpdateSubscriptionTestCase(BaseTestCase): self.assertTrue(mock.Subscription.create.called) + @patch("hc.payments.models.braintree") + def test_supporter_works(self, mock): + self._setup_mock(mock) + + self.profile.sms_limit = 0 + self.profile.sms_sent = 1 + self.profile.save() + + r = self.run_update("S5") + 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, "S5") + self.assertEqual(sub.plan_name, "Supporter ($5 / month)") + + # User's profile should have adjusted limits + self.profile.refresh_from_db() + self.assertEqual(self.profile.ping_log_limit, 1000) + self.assertEqual(self.profile.check_limit, 20) + self.assertEqual(self.profile.team_limit, 2) + self.assertEqual(self.profile.sms_limit, 5) + 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_yearly_works(self, mock): self._setup_mock(mock) @@ -133,7 +161,7 @@ class UpdateSubscriptionTestCase(BaseTestCase): self.assertEqual(self.profile.ping_log_limit, 100) self.assertEqual(self.profile.check_limit, 20) self.assertEqual(self.profile.team_limit, 2) - self.assertEqual(self.profile.sms_limit, 0) + self.assertEqual(self.profile.sms_limit, 5) self.assertTrue(mock.Subscription.cancel.called) diff --git a/hc/payments/views.py b/hc/payments/views.py index 74481be3..03a2cc09 100644 --- a/hc/payments/views.py +++ b/hc/payments/views.py @@ -110,7 +110,7 @@ def update(request): request.session["payment_method_status"] = "success" return redirect("hc-billing") - if plan_id not in ("", "P20", "P80", "Y192", "Y768"): + if plan_id not in ("", "P20", "P80", "Y192", "Y768", "S5", "S48"): return HttpResponseBadRequest() # Cancel the previous plan and reset limits: @@ -120,7 +120,7 @@ def update(request): profile.ping_log_limit = 100 profile.check_limit = 20 profile.team_limit = 2 - profile.sms_limit = 0 + profile.sms_limit = 5 profile.save() if plan_id == "": @@ -133,17 +133,24 @@ def update(request): # Update user's profile profile = request.user.profile - if plan_id in ("P20", "Y192"): + if plan_id in ("S5", "S48"): + profile.check_limit = 20 + profile.team_limit = 2 profile.ping_log_limit = 1000 + profile.sms_limit = 5 + profile.sms_sent = 0 + profile.save() + elif plan_id in ("P20", "Y192"): profile.check_limit = 100 profile.team_limit = 9 + profile.ping_log_limit = 1000 profile.sms_limit = 50 profile.sms_sent = 0 profile.save() elif plan_id in ("P80", "Y768"): - profile.ping_log_limit = 1000 profile.check_limit = 1000 profile.team_limit = 500 + profile.ping_log_limit = 1000 profile.sms_limit = 500 profile.sms_sent = 0 profile.save() diff --git a/static/css/billing.css b/static/css/billing.css index 6163a54c..0a96ea4b 100644 --- a/static/css/billing.css +++ b/static/css/billing.css @@ -13,7 +13,7 @@ @media (min-width: 992px) { #change-billing-plan-modal .modal-dialog, #payment-method-modal .modal-dialog, #please-wait-modal .modal-dialog { - width: 850px; + width: 900px; } } @@ -75,7 +75,7 @@ #change-billing-plan-modal .plan li { margin: 0; - padding: 0; + padding: 1px 0; } #change-billing-plan-modal .text-warning { @@ -89,5 +89,5 @@ #please-wait-modal .modal-body { text-align: center; padding: 100px; - font-size: 18px; -} \ No newline at end of file + font-size: 18px; +} diff --git a/static/css/pricing.css b/static/css/pricing.css index e4425c42..53f3a1f7 100644 --- a/static/css/pricing.css +++ b/static/css/pricing.css @@ -1,24 +1,64 @@ -.panel-pricing .list-group-item { - color: #777777; +#subscription-status form { + display: inline-block; } -.panel-pricing .list-group-item:last-child { - border-bottom-right-radius: 0px; - border-bottom-left-radius: 0px; + +#pricing-table { } -.panel-pricing .list-group-item:first-child { - border-top-right-radius: 0px; - border-top-left-radius: 0px; + + +.panel.plan h1 { + font-size: 24px; + font-weight: bold; + + display: inline-block; + line-height: 0.9; + text-shadow: 0px 1px white, -1px 1px white, 1px 1px white, -1px 0px white; } -.panel-pricing .panel-body { - font-size: 40px; - color: #777777; - padding: 20px; - margin: 0px; - background-color: #f0f0f0; + +.hobbyist h1 { + color: #0a220c; + border-bottom: 3px solid #A5D6A7; } -#subscription-status form { - display: inline-block; +.supporter h1 { + color: #1d190f; + border-bottom: 3px solid #FFE082; +} + +.business h1 { + color: #141c22; + border-bottom: 3px solid #90CAF9; +} + +.business-plus h1 { + color: #221f1e; + border-bottom: 3px solid #BCAAA4; +} + +.mo { + font-size: 16px; +} + +.plan .btn { + font-weight: bold; + color: #1ea65a; + border-color: #1ea65a; + background: #FFF; + transition: all 0.2s ease; + + border-radius: 5px; + padding: 8px 20px; +} + +.plan .btn:hover { + color: #fff; + background: #22bc66; + border-color: #22bc66; +} + +.plan .list-group-item:last-child { + border-bottom: 0; + } #payment-method-modal .modal-header { @@ -42,10 +82,6 @@ font-weight: bold; } -.mo { - font-size: 18px; - color: #888; -} #period-controls { text-align: center; diff --git a/static/js/billing.js b/static/js/billing.js index b805ebbe..a91b9ccb 100644 --- a/static/js/billing.js +++ b/static/js/billing.js @@ -32,9 +32,9 @@ $(function () { } $("#payment-form-submit").prop("disabled", true); - $("#payment-method-modal").modal("show"); + $("#payment-method-modal").modal("show"); - getToken(function(token) { + getToken(function(token) { braintree.dropin.create({ authorization: token, container: "#dropin", @@ -48,7 +48,7 @@ $(function () { instance.requestPaymentMethod(function (err, payload) { $("#payment-method-modal").modal("hide"); $("#please-wait-modal").modal("show"); - + $("#nonce").val(payload.nonce); $("#update-subscription-form").submit(); }); @@ -76,7 +76,7 @@ $(function () { }); $("#update-payment-method").click(function() { - showPaymentMethodForm($("#old-plan-id").val()); + showPaymentMethodForm($("#old-plan-id").val()); }); $("#billing-history").load("/accounts/profile/billing/history/"); @@ -98,6 +98,12 @@ $(function () { updateChangePlanForm(); }); + $("#plan-supporter").click(function() { + $(".plan").removeClass("selected"); + $("#plan-supporter").addClass("selected"); + updateChangePlanForm(); + }); + $("#plan-business").click(function() { $(".plan").removeClass("selected"); $("#plan-business").addClass("selected"); @@ -116,6 +122,7 @@ $(function () { // "Monthly" is selected: dispplay monthly prices if ($("#billing-monthly").is(":checked")) { var period = "monthly"; + $("#supporter-price").text("$5"); $("#business-price").text("$20"); $("#business-plus-price").text("$80"); } @@ -123,6 +130,7 @@ $(function () { // "Annual" is selected: dispplay annual prices if ($("#billing-annual").is(":checked")) { var period = "annual"; + $("#supporter-price").text("$4"); $("#business-price").text("$16"); $("#business-plus-price").text("$64"); } @@ -132,6 +140,11 @@ $(function () { planId = ""; } + // "Supporter" is selected, set planId + if ($("#plan-supporter").hasClass("selected")) { + planId = period == "monthly" ? "S5" : "S48"; + } + // "Business" is selected, set planId if ($("#plan-business").hasClass("selected")) { planId = period == "monthly" ? "P20" : "Y192"; @@ -141,7 +154,7 @@ $(function () { if ($("#plan-business-plus").hasClass("selected")) { planId = period == "monthly" ? "P80" : "Y768"; } - + if (planId == $("#old-plan-id").val()) { $("#change-plan-btn") .attr("disabled", "disabled") diff --git a/static/js/pricing.js b/static/js/pricing.js index 8fb5a53d..6c17514a 100644 --- a/static/js/pricing.js +++ b/static/js/pricing.js @@ -1,13 +1,15 @@ $(function () { $("#period-controls :input").change(function() { if (this.value == "monthly") { - $("#s-price").text("$20"); - $("#p-price").text("$80"); + $("#supporter-price").text("$5"); + $("#business-price").text("$20"); + $("#business-plus-price").text("$80"); } if (this.value == "annual") { - $("#s-price").text("$16"); - $("#p-price").text("$64"); + $("#supporter-price").text("$4"); + $("#business-price").text("$16"); + $("#business-plus-price").text("$64"); } }); }); \ No newline at end of file diff --git a/templates/accounts/billing.html b/templates/accounts/billing.html index 5131baf7..233c3053 100644 --- a/templates/accounts/billing.html +++ b/templates/accounts/billing.html @@ -176,27 +176,43 @@