Created
July 16, 2018 15:46
-
-
Save lakesare/03213078d26c97d8bb7606d45ca1d67f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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