From f226c551a88bfd18832251ddc66e3b62b50a5a2b Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 00:06:21 +0100 Subject: [PATCH 01/22] Add stripe_subscription_id field to MembershipOrder --- ..._membershiporder_stripe_subscription_id.py | 20 +++++++++++++++++++ digitalglarus/models.py | 3 +++ 2 files changed, 23 insertions(+) create mode 100644 digitalglarus/migrations/0025_membershiporder_stripe_subscription_id.py diff --git a/digitalglarus/migrations/0025_membershiporder_stripe_subscription_id.py b/digitalglarus/migrations/0025_membershiporder_stripe_subscription_id.py new file mode 100644 index 00000000..127d5ff8 --- /dev/null +++ b/digitalglarus/migrations/0025_membershiporder_stripe_subscription_id.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2017-12-23 22:56 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('digitalglarus', '0024_bookingcancellation'), + ] + + operations = [ + migrations.AddField( + model_name='membershiporder', + name='stripe_subscription_id', + field=models.CharField(max_length=100, null=True), + ), + ] diff --git a/digitalglarus/models.py b/digitalglarus/models.py index 16d6b639..9cae88ed 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -129,6 +129,7 @@ class MembershipOrder(Ordereable, models.Model): membership = models.ForeignKey(Membership) start_date = models.DateField() end_date = models.DateField() + stripe_subscription_id = models.CharField(max_length=100, null=True) @classmethod def current_membership_dates(cls, user): @@ -172,10 +173,12 @@ class MembershipOrder(Ordereable, models.Model): @classmethod def create(cls, data): stripe_charge = data.pop('stripe_charge', None) + stripe_subscription_id = data.pop('stripe_subscription_id', None) instance = cls.objects.create(**data) instance.stripe_charge_id = stripe_charge.id instance.last4 = stripe_charge.source.last4 instance.cc_brand = stripe_charge.source.brand + instance.stripe_subscription_id = stripe_subscription_id instance.save() return instance From 872582f45ff3dc977726d8473320a47376dab0f0 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 00:08:17 +0100 Subject: [PATCH 02/22] Add tentative code to subscribe customer to Stripe plan (wip) --- digitalglarus/views.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 96983d9b..a45defd3 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -375,6 +375,28 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): }) return render(request, self.template_name, context) + # Subscribe the customer to dg plan from the next month onwards + stripe_plan = stripe_utils.get_or_create_stripe_plan( + amount=membership_type.price, + name='Digital Glarus {sub_type_name} Subscription'.format( + sub_type_name=membership_type.name + ), + stripe_plan_id='dg-{sub_type_name}'.format( + sub_type_name=membership_type.name + ) + ) + subscription_result = stripe_utils.subscribe_customer_to_plan( + customer.stripe_id, + [{"plan": stripe_plan.get('response_object').stripe_plan_id}] + ) + stripe_subscription_obj = subscription_result.get( + 'response_object' + ) + # Check if the subscription was approved and is active + if (stripe_subscription_obj is None + or stripe_subscription_obj.status != 'active'): + pass + charge = charge_response.get('response_object') if 'source' in charge: cardholder_name = charge['source']['name'] From b2d0fd45ad5d6234537b408bbc242b48dc66f55a Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 00:21:25 +0100 Subject: [PATCH 03/22] Fix PEP8 error --- digitalglarus/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index a45defd3..017dd090 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -393,8 +393,8 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): 'response_object' ) # Check if the subscription was approved and is active - if (stripe_subscription_obj is None - or stripe_subscription_obj.status != 'active'): + if (stripe_subscription_obj is None or + stripe_subscription_obj.status != 'active'): pass charge = charge_response.get('response_object') From 6fa8dbb5cb4a20f487f45cbf24f668c6149da7b5 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:32:08 +0100 Subject: [PATCH 04/22] Add trial_end parameter to subscribe_customer_to_plan --- utils/stripe_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index 58840be0..79bca243 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -210,12 +210,14 @@ class StripeUtils(object): return return_value @handleStripeError - def subscribe_customer_to_plan(self, customer, plans): + def subscribe_customer_to_plan(self, customer, plans, trial_end=None): """ Subscribes the given customer to the list of given plans :param customer: The stripe customer identifier :param plans: A list of stripe plans. + :param trial_end: An integer representing when the Stripe subscription + is supposed to end Ref: https://stripe.com/docs/api/python#create_subscription-items e.g. plans = [ @@ -227,8 +229,7 @@ class StripeUtils(object): """ subscription_result = self.stripe.Subscription.create( - customer=customer, - items=plans, + customer=customer, items=plans, trial_end=trial_end ) return subscription_result From 009128135711a80ccdef58026e82462d7d31ccaf Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:45:59 +0100 Subject: [PATCH 05/22] Add next_month_in_sec_since_epoch MembershipType function --- digitalglarus/models.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/digitalglarus/models.py b/digitalglarus/models.py index 9cae88ed..ffd98029 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -59,6 +59,17 @@ class MembershipType(models.Model): return "{} - {}".format(datetime.strftime(start_date, "%b, %d %Y"), datetime.strftime(end_date, "%b, %d %Y")) + @cached_property + def next_month_in_sec_since_epoch(self): + """ + First day of the next month expressed in seconds since the epoch time + :return: Time in seconds + """ + start_date, end_date = self.first_month_range + first_day_next_month = end_date + timedelta(days=1) + epoch_time = int(time.mktime(first_day_next_month.timetuple())) + return epoch_time + class Membership(models.Model): type = models.ForeignKey(MembershipType) From 11b8ebe401919d635e2908c24191bbeb072252a9 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:46:36 +0100 Subject: [PATCH 06/22] Import time --- digitalglarus/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/digitalglarus/models.py b/digitalglarus/models.py index ffd98029..39ee356e 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -1,6 +1,7 @@ import calendar +import time from datetime import datetime, date, timedelta from dateutil.relativedelta import relativedelta from django.db import models From 3826ca207ae7c08b6d3628c404403e8538d9957c Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:48:03 +0100 Subject: [PATCH 07/22] Reformat code --- digitalglarus/views.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 017dd090..4efa21db 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -355,16 +355,21 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): membership_type = data.get('membership_type') # Get or create stripe customer - customer = StripeCustomer.get_or_create(email=self.request.user.email, - token=token) + customer = StripeCustomer.get_or_create( + email=self.request.user.email, token=token + ) if not customer: form.add_error("__all__", "Invalid credit card") - return self.render_to_response(self.get_context_data(form=form)) + return self.render_to_response( + self.get_context_data(form=form) + ) # Make stripe charge to a customer stripe_utils = StripeUtils() - charge_response = stripe_utils.make_charge(amount=membership_type.first_month_price, - customer=customer.stripe_id) + charge_response = stripe_utils.make_charge( + amount=membership_type.first_month_price, + customer=customer.stripe_id + ) charge = charge_response.get('response_object') # Check if the payment was approved From f5170cce5f9f88739f792cc653fd3497be0cb09a Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:51:16 +0100 Subject: [PATCH 08/22] Call DG subscribe_customer_to_plan with trial period until first of next month --- digitalglarus/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 4efa21db..ff567036 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -392,7 +392,8 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): ) subscription_result = stripe_utils.subscribe_customer_to_plan( customer.stripe_id, - [{"plan": stripe_plan.get('response_object').stripe_plan_id}] + [{"plan": stripe_plan.get('response_object').stripe_plan_id}], + trial_end=membership_type.next_month_in_sec_since_epoch ) stripe_subscription_obj = subscription_result.get( 'response_object' From 3ed6119dc9b58536d0a22aa998a9006d77090489 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:53:23 +0100 Subject: [PATCH 09/22] Check if DG subscription created was under trial; if not show error --- digitalglarus/views.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index ff567036..e163359c 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -398,10 +398,18 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): stripe_subscription_obj = subscription_result.get( 'response_object' ) - # Check if the subscription was approved and is active + # Check if call to create subscription was ok if (stripe_subscription_obj is None or - stripe_subscription_obj.status != 'active'): - pass + ( + stripe_subscription_obj.status != 'active' and + stripe_subscription_obj.status != 'trialing' + ) + ): + context.update({ + 'paymentError': subscription_result.get('error'), + 'form': form + }) + return render(request, self.template_name, context) charge = charge_response.get('response_object') if 'source' in charge: From f6d0b6ce9c32e03ec0a3b4ea87125a7f581036b7 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 12:54:59 +0100 Subject: [PATCH 10/22] Add stripe_subscription_id to MembershipOrder data --- digitalglarus/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index e163359c..d3e69e99 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -448,6 +448,7 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): 'customer': customer, 'billing_address': billing_address, 'stripe_charge': charge, + 'stripe_subscription_id': stripe_subscription_obj.id, 'amount': membership_type.first_month_price, 'start_date': membership_start_date, 'end_date': membership_end_date From b4421bc9b2eda0b69e5e3b6de10318d944e5df99 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 13:06:23 +0100 Subject: [PATCH 11/22] Reformat code --- digitalglarus/models.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/digitalglarus/models.py b/digitalglarus/models.py index 39ee356e..e41098ac 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -83,9 +83,10 @@ class Membership(models.Model): @classmethod def get_current_membership(cls, user): - - has_order_current_month = Q(membershiporder__customer__user=user, - membershiporder__created_at__month=datetime.today().month) + has_order_current_month = Q( + membershiporder__customer__user=user, + membershiporder__created_at__month=datetime.today().month + ) # import pdb;pdb.set_trace() return cls.objects.\ filter(has_order_current_month).last() @@ -108,18 +109,23 @@ class Membership(models.Model): def activate_or_crete(cls, data, user): membership = cls.get_by_user(user) membership_id = membership.id if membership else None - obj, created = cls.objects.update_or_create(id=membership_id, defaults=data) + obj, created = cls.objects.update_or_create( + id=membership_id, defaults=data + ) return obj @classmethod def is_digitalglarus_active_member(cls, user): # past_month = (datetime.today() - relativedelta(months=1)).month - has_order_current_month = Q(membershiporder__customer__user=user, - membershiporder__created_at__month=datetime.today().month) + has_order_current_month = Q( + membershiporder__customer__user=user, + membershiporder__created_at__month=datetime.today().month + ) # has_order_past_month = Q(membershiporder__customer__user=user, # membershiporder__created_at__month=past_month) active_membership = Q(active=True) - # return cls.objects.filter(has_order_past_month | has_order_current_month).\ + # return cls.objects.filter( + # has_order_past_month | has_order_current_month).\ return cls.objects.filter(has_order_current_month).\ filter(active_membership).exists() From b19c3bdcde730bbbb375e6ed0532d4396e939a1d Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 13:15:48 +0100 Subject: [PATCH 12/22] Reformat code --- digitalglarus/models.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/digitalglarus/models.py b/digitalglarus/models.py index e41098ac..743457d1 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -88,8 +88,7 @@ class Membership(models.Model): membershiporder__created_at__month=datetime.today().month ) # import pdb;pdb.set_trace() - return cls.objects.\ - filter(has_order_current_month).last() + return cls.objects.filter(has_order_current_month).last() # def get_current_active_membership(cls, user): # membership = cls.get_current_membership(user) @@ -97,8 +96,7 @@ class Membership(models.Model): @classmethod def get_by_user(cls, user): - return cls.objects.\ - filter(membershiporder__customer__user=user).last() + return cls.objects.filter(membershiporder__customer__user=user).last() @classmethod def create(cls, data): From 63215b1c42be0c663b7bbf76ef935c37c0ec9f17 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 13:35:53 +0100 Subject: [PATCH 13/22] Organize imports --- digitalglarus/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/digitalglarus/models.py b/digitalglarus/models.py index 743457d1..fc4289aa 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -1,7 +1,6 @@ - - import calendar import time + from datetime import datetime, date, timedelta from dateutil.relativedelta import relativedelta from django.db import models From 707e1897b3b1e02c89eba1de3e383d452993e62e Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 14:23:33 +0100 Subject: [PATCH 14/22] Reorganize imports --- digitalglarus/views.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index d3e69e99..fc5186f4 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -9,20 +9,31 @@ from django.utils.translation import get_language from djangocms_blog.models import Post from django.contrib import messages from django.views.generic import DetailView, ListView -from .models import Supporter -from .mixins import ChangeMembershipStatusMixin from utils.forms import ContactUsForm from utils.mailer import BaseEmail from django.views.generic.edit import FormView from membership.models import StripeCustomer -from utils.views import LoginViewMixin, SignupViewMixin, \ - PasswordResetViewMixin, PasswordResetConfirmViewMixin -from utils.forms import PasswordResetRequestForm, UserBillingAddressForm, EditCreditCardForm +from utils.views import ( + LoginViewMixin, SignupViewMixin, PasswordResetViewMixin, + PasswordResetConfirmViewMixin +) +from utils.forms import ( + PasswordResetRequestForm, UserBillingAddressForm, EditCreditCardForm +) from utils.stripe_utils import StripeUtils from utils.models import UserBillingAddress -from .forms import LoginForm, SignupForm, MembershipBillingForm, BookingDateForm,\ +from .forms import ( + LoginForm, SignupForm, MembershipBillingForm, BookingDateForm, BookingBillingForm, CancelBookingForm +) +from .models import ( + MembershipType, Membership, MembershipOrder, Booking, BookingPrice, + BookingOrder, BookingCancellation, Supporter +) +from .mixins import ( + MembershipRequiredMixin, IsNotMemberMixin, ChangeMembershipStatusMixin +) from .models import MembershipType, Membership, MembershipOrder, Booking, BookingPrice,\ BookingOrder, BookingCancellation From 29c24574aa4e67e76e30ae3a64d0e7c16acb15ba Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 14:25:04 +0100 Subject: [PATCH 15/22] Cancel subscription on membership deactivation + some more reorganizes + import logger --- digitalglarus/views.py | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index fc5186f4..7576eb36 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -1,3 +1,5 @@ +import logging + from django.conf import settings from django.shortcuts import render from django.http import HttpResponseRedirect @@ -35,10 +37,7 @@ from .mixins import ( MembershipRequiredMixin, IsNotMemberMixin, ChangeMembershipStatusMixin ) -from .models import MembershipType, Membership, MembershipOrder, Booking, BookingPrice,\ - BookingOrder, BookingCancellation - -from .mixins import MembershipRequiredMixin, IsNotMemberMixin +logger = logging.getLogger(__name__) class IndexView(TemplateView): @@ -282,7 +281,6 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView): booking_data = { 'start_date': start_date, 'end_date': end_date, - 'start_date': start_date, 'free_days': free_days, 'price': normal_price, 'final_price': final_price, @@ -529,8 +527,29 @@ class MembershipDeactivateView(LoginRequiredMixin, UpdateView): def post(self, *args, **kwargs): membership = self.get_object() membership.deactivate() - - messages.add_message(self.request, messages.SUCCESS, self.success_message) + messages.add_message( + self.request, messages.SUCCESS, self.success_message + ) + # cancel Stripe subscription + stripe_utils = StripeUtils() + membership_order = MembershipOrder.objects.filter( + customer__user=self.request.user + ).last() + if membership_order.subscription_id: + result = stripe_utils.unsubscribe_customer( + subscription_id=membership_order.subscription_id + ) + stripe_subscription_obj = result.get('response_object') + # Check if the subscription was canceled + if (stripe_subscription_obj is None or + stripe_subscription_obj.status != 'canceled'): + error_msg = result.get('error') + logger.error( + "Could not cancel Digital Glarus subscription. Reason: " + "{reason}".format( + reason=error_msg + ) + ) return HttpResponseRedirect(self.success_url) From eb067f57084325e518b607fa72a776842c1c7d31 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 14:38:32 +0100 Subject: [PATCH 16/22] Refactor code and log messages for possible errors --- digitalglarus/views.py | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 7576eb36..fa601d8d 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -535,21 +535,35 @@ class MembershipDeactivateView(LoginRequiredMixin, UpdateView): membership_order = MembershipOrder.objects.filter( customer__user=self.request.user ).last() - if membership_order.subscription_id: - result = stripe_utils.unsubscribe_customer( - subscription_id=membership_order.subscription_id - ) - stripe_subscription_obj = result.get('response_object') - # Check if the subscription was canceled - if (stripe_subscription_obj is None or - stripe_subscription_obj.status != 'canceled'): - error_msg = result.get('error') + if membership_order: + if membership_order.subscription_id: + result = stripe_utils.unsubscribe_customer( + subscription_id=membership_order.subscription_id + ) + stripe_subscription_obj = result.get('response_object') + # Check if the subscription was canceled + if (stripe_subscription_obj is None or + stripe_subscription_obj.status != 'canceled'): + error_msg = result.get('error') + logger.error( + "Could not cancel Digital Glarus subscription. " + "Reason: {reason}".format( + reason=error_msg + ) + ) + else: logger.error( - "Could not cancel Digital Glarus subscription. Reason: " - "{reason}".format( - reason=error_msg + "User {user} may have Stripe subscriptions created " + "manually. Please check.".format( + user=self.request.user.name ) ) + else: + logger.error( + "MembershipOrder for {user} not found".format( + user=self.request.user.name + ) + ) return HttpResponseRedirect(self.success_url) From 89d70a2b6a1642ef1d9028f1efdc903139a6e192 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 15:04:20 +0100 Subject: [PATCH 17/22] Fix bug: rename subscription_id to stripe_subscription_id --- digitalglarus/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index fa601d8d..2bb1ee32 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -536,9 +536,9 @@ class MembershipDeactivateView(LoginRequiredMixin, UpdateView): customer__user=self.request.user ).last() if membership_order: - if membership_order.subscription_id: + if membership_order.stripe_subscription_id: result = stripe_utils.unsubscribe_customer( - subscription_id=membership_order.subscription_id + subscription_id=membership_order.stripe_subscription_id ) stripe_subscription_obj = result.get('response_object') # Check if the subscription was canceled From ca2a90ca2d88f1000437caa6620ceb68d4f54aba Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 18:06:17 +0100 Subject: [PATCH 18/22] On reactivate, take user to pricing page --- .../templates/digitalglarus/membership_orders_list.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/digitalglarus/templates/digitalglarus/membership_orders_list.html b/digitalglarus/templates/digitalglarus/membership_orders_list.html index ceeea6f1..ccce1121 100644 --- a/digitalglarus/templates/digitalglarus/membership_orders_list.html +++ b/digitalglarus/templates/digitalglarus/membership_orders_list.html @@ -95,10 +95,10 @@ Deactivate {% elif not current_membership.active %} -
- {% csrf_token %} + + {% csrf_token %}
- +
{% endif %} From a34bd83c5e2d174d26c3fae601510c0e25fe8727 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 18:07:30 +0100 Subject: [PATCH 19/22] Refactor reactivate link html --- .../templates/digitalglarus/membership_orders_list.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/digitalglarus/templates/digitalglarus/membership_orders_list.html b/digitalglarus/templates/digitalglarus/membership_orders_list.html index ccce1121..dd49837d 100644 --- a/digitalglarus/templates/digitalglarus/membership_orders_list.html +++ b/digitalglarus/templates/digitalglarus/membership_orders_list.html @@ -95,12 +95,9 @@ Deactivate {% elif not current_membership.active %} -
- {% csrf_token %}
- + Reactivate
-
{% endif %} {% else %}
From a3f212a59ea090fd1f8da6947f72d3e696b06cbe Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 24 Dec 2017 18:33:24 +0100 Subject: [PATCH 20/22] Fix PEP8 error --- digitalglarus/views.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 2bb1ee32..3b12934f 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -409,11 +409,8 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): ) # Check if call to create subscription was ok if (stripe_subscription_obj is None or - ( - stripe_subscription_obj.status != 'active' and - stripe_subscription_obj.status != 'trialing' - ) - ): + (stripe_subscription_obj.status != 'active' and + stripe_subscription_obj.status != 'trialing')): context.update({ 'paymentError': subscription_result.get('error'), 'form': form From 31895688849eabf3124c075293045f692e518400 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 27 Dec 2017 20:04:20 +0100 Subject: [PATCH 21/22] Send emails to admin when Stripe transaction error --- digitalglarus/views.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 3b12934f..32d8e1f5 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -24,6 +24,7 @@ from utils.forms import ( ) from utils.stripe_utils import StripeUtils from utils.models import UserBillingAddress +from utils.tasks import send_plain_email_task from .forms import ( LoginForm, SignupForm, MembershipBillingForm, BookingDateForm, @@ -387,6 +388,18 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): 'paymentError': charge_response.get('error'), 'form': form }) + email_to_admin_data = { + 'subject': "Could not create charge for Digital Glarus " + "user: {user}".format( + user=self.request.user.email + ), + 'from_email': 'info@digitalglarus.ch', + 'to': ['info@ungleich.ch'], + 'body': "\n".join( + ["%s=%s" % (k, v) for (k, v) in + charge_response.items()]), + } + send_plain_email_task.delay(email_to_admin_data) return render(request, self.template_name, context) # Subscribe the customer to dg plan from the next month onwards @@ -415,6 +428,18 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): 'paymentError': subscription_result.get('error'), 'form': form }) + email_to_admin_data = { + 'subject': "Could not create Stripe subscription for " + "Digital Glarus user: {user}".format( + user=self.request.user.email + ), + 'from_email': 'info@digitalglarus.ch', + 'to': ['info@ungleich.ch'], + 'body': "\n".join( + ["%s=%s" % (k, v) for (k, v) in + subscription_result.items()]), + } + send_plain_email_task.delay(email_to_admin_data) return render(request, self.template_name, context) charge = charge_response.get('response_object') From 0abd165c8e32c0ed0db3a388f32b3de89a938ba4 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 27 Dec 2017 20:21:37 +0100 Subject: [PATCH 22/22] Skip test_post if Stripe API key is not provided --- digitalglarus/test_views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/digitalglarus/test_views.py b/digitalglarus/test_views.py index cdd23bad..b7fc6c3a 100644 --- a/digitalglarus/test_views.py +++ b/digitalglarus/test_views.py @@ -1,5 +1,5 @@ from model_mommy import mommy -from unittest import mock +from unittest import mock, skipIf from django.test import TestCase from django.conf import settings @@ -126,6 +126,11 @@ class MembershipPaymentViewTest(BaseTestCase): self.assertEqual(response.context['membership_type'], self.membership_type) + @skipIf( + settings.STRIPE_API_PRIVATE_KEY_TEST is None or + settings.STRIPE_API_PRIVATE_KEY_TEST is "", + """Stripe details unavailable, so skipping CeleryTaskTestCase""" + ) @mock.patch('utils.stripe_utils.StripeUtils.create_customer') def test_post(self, stripe_mocked_call):