Skip to content

Instantly share code, notes, and snippets.

@lakesare
Created July 16, 2018 15:46
Show Gist options
  • Save lakesare/03213078d26c97d8bb7606d45ca1d67f to your computer and use it in GitHub Desktop.
Save lakesare/03213078d26c97d8bb7606d45ca1d67f to your computer and use it in GitHub Desktop.
class UserBillingInfo(models.Model):
user = models.OneToOneField(User, unique=True)
payment_token = models.CharField(max_length = 20)
is_current = models.BooleanField(default = False)
active_until = models.DateField( default=datetime.now()+timedelta(days=365), null=True, blank=True )
billing_phone = models.DecimalField(default=0, max_digits=12, decimal_places=0)
billing_address = models.CharField(max_length = 160)
billing_city = models.CharField(max_length = 38)
billing_zip = models.PositiveIntegerField(default = 0)
billing_state = models.CharField(max_length = 2)
billing_country = models.CharField(max_length = 38)
card_name = models.CharField(max_length = 50, null=True)
card_brand = models.CharField(max_length = 10, null=True)
card_exp_month = models.CharField(max_length = 2, null=True)
card_exp_year = models.CharField(max_length = 4, null=True)
card_last4 = models.CharField(max_length = 4, null=True)
card_cvv = models.CharField(max_length = 4, null=True)
# stripe.Customer id!
stripe_id = models.CharField(max_length = 50)
stripe_card_id = models.CharField(max_length = 50, null=True)
stripe_plan_id = models.CharField(max_length = 50, null=True)
stripe_sub_id = models.CharField(max_length = 50, null=True)
activate_date = models.DateTimeField(auto_now_add=True)
max_active_users = models.PositiveIntegerField(default = 0)
custom_price = models.PositiveIntegerField(default = 0)
@staticmethod
def derive_custom_stripe_plan_id_from_interval(interval):
if interval == 'Monthly': return '6666'
elif interval == 'Yearly': return '7777'
@staticmethod
def create_with_stripe(user, stripe_token, stripe_plan_id, custom_plan_fields):
stripe_customer = stripe.Customer.create(
source=stripe_token, # obtained from Stripe.js
email=user.email
)
stripe_subscription = stripe.Subscription.create(
customer=stripe_customer.id,
plan=stripe_plan_id,
# fields for the custom stripe_plan_id
**({
'quantity': custom_plan_fields['subscription_cost']
} if custom_plan_fields else {})
)
user_billing_info = UserBillingInfo.objects.create(**UserBillingInfo.derive_fields_from_stripe(user, stripe_customer.id, custom_plan_fields))
return user_billing_info
def update_with_stripe(self, stripe_token, stripe_plan_id, custom_plan_fields):
# update stripe.Customer's source
stripe_customer = stripe.Customer.retrieve(self.stripe_id)
stripe_customer.source = stripe_token
stripe_customer.save()
# update stripe.Subscription
stripe_subscription = stripe.Subscription.retrieve(self.stripe_sub_id)
stripe_subscription.plan = stripe_plan_id
if custom_plan_fields:
stripe_subscription.quantity = custom_plan_fields['subscription_cost']
stripe_subscription.save()
# update user_billing_info
# ___why not self.update?
# because there is no such method in django.
# ___why not Model.objects.filter(id=self.id).update(**my_data_dict)
# seems inefficient.
user_billing_info_fields_to_update = UserBillingInfo.derive_fields_from_stripe(self.user, stripe_customer.id, custom_plan_fields)
for (key, value) in user_billing_info_fields_to_update.items():
setattr(self, key, value)
return self.save()
def get_price_of_subscription(self):
# if it's a custom subscription
if SubscriptionPlan.if_custom_stripe_plan_id(self.stripe_plan_id):
# should always be same with stripe.Subscription.quantity
return self.custom_price
else:
subscription_plan = SubscriptionPlan.objects.get(stripe_plan_id = self.stripe_plan_id)
return subscription_plan.price
@staticmethod
def derive_fields_from_stripe(user, stripe_customer_id, custom_plan_fields):
stripe_customer = stripe.Customer.retrieve(stripe_customer_id)
stripe_source = stripe_customer.sources.data[0]
stripe_subscription = stripe_customer.subscriptions.data[0]
fields = {
'user' : user,
'is_current' : True,
'active_until' : datetime.now() + timedelta(days=365),
'card_cvv' : None, # let's not save card_cvv anymore, it's illegal
'activate_date': datetime.now(),
'stripe_id' : stripe_customer.id,
'stripe_card_id': stripe_customer.default_source,
'card_name' : stripe_source.name,
'card_brand' : stripe_source.brand,
'card_exp_month': stripe_source.exp_month,
'card_exp_year' : stripe_source.exp_year,
'card_last4' : stripe_source.last4,
'stripe_plan_id': stripe_subscription.plan.id,
'stripe_sub_id' : stripe_subscription.id
}
# only used for custom stripe_plan_id's
if custom_plan_fields:
fields['max_active_users'] = custom_plan_fields['max_active_users']
fields['custom_price'] = custom_plan_fields['subscription_cost']
return fields
def send_order_summary(self, subject=""):
subscription_plan = SubscriptionPlan.objects.get(stripe_plan_id=self.stripe_plan_id)
user_profile = UserProfile.objects.get(user = self.user)
if subscription_plan.interval == 'Monthly': frequency = '/mo'
else: frequency = '/yr'
price = self.get_price_of_subscription()
certcentral2.services.send_email.send_email(
template_path='/static/emails/order_summary.html',
template_format_vars=[
user_profile.get_full_name(),
subscription_plan.name,
'$' + str(price) + frequency,
datetime.today().strftime('%B %-d, %Y'),
self.user.email
],
to="CertCentral <" + self.user.email + ">",
subject=subject
)
from certcentral2.models import *
from django.http import JsonResponse
import stripe
from django.contrib.auth import authenticate, login
from shared.services.custom_subscription_link import CustomSubscriptionLink
import code
def api_pricing_payment_setup(request, stripe_plan_id):
stripe_token = request.POST.get('stripeToken')
if request.GET.get('subscription_code'):
# ___why do we need to reassign stripe_plan_id?
# stripe_plan_id here can be either noncustom, or Enterprise. Because that's what we allow a creation of subscription_code for.
# - if it is enterprise - leave it as such, it's a custom plan too!
# - if it's a noncustom stripe_plan_id however, and we do have custom_plan_fields - we have to switch to either Monthly, or Yearly stripe plan.
if SubscriptionPlan.if_noncustom_stripe_plan_id(stripe_plan_id):
inspirational_subscription_plan = SubscriptionPlan.objects.get(stripe_plan_id=stripe_plan_id)
stripe_plan_id = UserBillingInfo.derive_custom_stripe_plan_id_from_interval(inspirational_subscription_plan.interval)
custom_plan_fields = CustomSubscriptionLink.parse(request)
else: custom_plan_fields = None
if request.user.is_authenticated():
update_subscriptions_of_existing_user(request.user, stripe_plan_id, stripe_token, custom_plan_fields)
else:
# do we already have a user with such an email?
email = request.POST.get('email')
password = request.POST.get('password')
try:
user_found_by_email_from_card = User.objects.get(email=email)
# try to authenticate
old_user = authenticate(username=user_found_by_email_from_card.username, password=password)
if old_user is not None:
update_subscriptions_of_existing_user(old_user, stripe_plan_id, stripe_token, custom_plan_fields)
login(request, old_user)
else:
return JsonResponse({ 'message': "The email you entered already exists, but password doesn't match it. Please try again." }, status=400)
except (ValueError, User.DoesNotExist):
first_name = request.POST.get('first-name')
last_name = request.POST.get('last-name')
confirm_email = request.POST.get('confirm-email')
if email == confirm_email:
# create user and user_profile
user_profile = UserProfile.create_user_and_profile(email, password, first_name, last_name, stripe_plan_id)
# create stripe.Customer, stripe.Subscription, and user_billing_info
user_billing_info = UserBillingInfo.create_with_stripe(user_profile.user, stripe_token, stripe_plan_id, custom_plan_fields)
user_billing_info.send_order_summary(subject="Welcome to CertCentral")
new_user = authenticate(username=user_profile.user.username, password=password)
login(request, new_user)
else:
return JsonResponse({ 'message': "The email addresses entered do not match. Please try again." }, status=400)
return JsonResponse({ 'status': 200 })
def update_subscriptions_of_existing_user(user, stripe_plan_id, stripe_token, custom_plan_fields):
# update user.role with stripe_plan_id
user_profile = UserProfile.objects.get(user_id=user)
user_profile.role = UserProfile.get_role_by_stripe_plan_id(stripe_plan_id)
user_profile.save()
# update user_billing_info
user_billing_info = UserBillingInfo.objects.get(user=user)
user_billing_info.update_with_stripe(stripe_token, stripe_plan_id, custom_plan_fields)
# update stripe.Subscription
stripe_subscription = stripe.Subscription.retrieve(user_billing_info.stripe_sub_id)
stripe_subscription.plan = stripe_plan_id
stripe_subscription.save()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment