Handle IncompleteSubscriptions in webhook

This commit is contained in:
PCoder 2020-12-23 10:59:21 +05:30
parent c4c918d591
commit 17c8f9ca18
3 changed files with 130 additions and 60 deletions

View file

@ -1,6 +1,7 @@
import logging
import json
import stripe
from django import forms
from django.conf import settings
from django.contrib import messages
@ -19,9 +20,8 @@ from hosting.forms import (
)
from hosting.models import (
HostingBill, HostingOrder, UserCardDetail, GenericProduct, UserHostingKey,
StripeTaxRate)
StripeTaxRate, IncompleteSubscriptions)
from membership.models import CustomUser, StripeCustomer
from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VMTemplateSerializer
from utils.forms import (
BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm,
@ -894,6 +894,53 @@ class OrderConfirmationView(DetailView, FormView):
latest_invoice = stripe.Invoice.retrieve(
stripe_subscription_obj.latest_invoice)
new_user_hosting_key_id = None
card_id = None
generic_payment_type = None
generic_payment_details = None
if 'generic_payment_details' in request.session:
generic_payment_details = request.session[
'generic_payment_details']
if 'generic_payment_type' in request.session:
generic_payment_type = request.session['generic_payment_type']
if 'new_user_hosting_key_id' in self.request.session:
new_user_hosting_key_id = request.session[
'new_user_hosting_key_id']
if 'card_id' in request.session:
card_id = request.session.get('card_id')
req = {
'scheme': self.request.scheme,
'host': self.request.get_host(),
'language': get_language(),
'new_user_hosting_key_id': new_user_hosting_key_id,
'card_id': card_id,
'generic_payment_type': generic_payment_type,
'generic_payment_details': generic_payment_details
}
subscription_status = ''
if stripe_subscription_obj:
subscription_status = stripe_subscription_obj.status
# Store params so that they can be retrieved later
IncompleteSubscriptions.objects.create(
subscription_status=subscription_status,
name=user.get('name'),
email=user.get('email'),
request=json.dumps(req),
stripe_api_cus_id=stripe_api_cus_id,
card_details_response=json.dumps(card_details_response),
stripe_subscription_obj=json.dumps(stripe_subscription_obj) if stripe_customer_obj else '',
stripe_onetime_charge=json.dumps(stripe_onetime_charge) if stripe_onetime_charge else '',
gp_details=json.dumps(gp_details) if gp_details else '',
specs=json.dumps(specs) if specs else '',
vm_template_id=vm_template_id if vm_template_id else 0,
template=json.dumps(template) if template else '',
billing_address_data=json.dumps(
request.session.get('billing_address_data')
)
)
# Check if the subscription was approved and is active
if (stripe_subscription_obj is None
or (stripe_subscription_obj.status != 'active'
@ -953,6 +1000,7 @@ class OrderConfirmationView(DetailView, FormView):
)
}
}
clear_all_session_vars(request)
return JsonResponse(context)
else:
logger.debug(
@ -962,28 +1010,6 @@ class OrderConfirmationView(DetailView, FormView):
"requires_source_action")
msg = subscription_result.get('error')
return show_error(msg, self.request)
new_user_hosting_key_id = None
card_id = None
generic_payment_type = None
generic_payment_details = None
if 'generic_payment_details' in request.session:
generic_payment_details = request.session['generic_payment_details']
if 'generic_payment_type' in request.session:
generic_payment_type = request.session['generic_payment_type']
if 'new_user_hosting_key_id' in self.request.session:
new_user_hosting_key_id = request.session['new_user_hosting_key_id']
if 'card_id' in request.session:
card_id = request.session.get('card_id')
req = {
'scheme': self.request.scheme,
'host': self.request.get_host(),
'language': get_language(),
'new_user_hosting_key_id': new_user_hosting_key_id,
'card_id': card_id,
'generic_payment_type': generic_payment_type,
'generic_payment_details': generic_payment_details
}
do_create_vm(req, user, stripe_api_cus_id,
card_details_response, stripe_subscription_obj,
stripe_onetime_charge, gp_details, specs, vm_template_id,
@ -1191,14 +1217,14 @@ def do_create_vm(request, user, stripe_api_cus_id, card_details_response,
"We have just received a payment of CHF {amount:.2f}"
" from you.{recurring}\n\n"
"Cheers,\nYour Data Center Light team".format(
name=user.get('name'),
amount=gp_details['amount'],
recurring=(
recurring_text
if gp_details['recurring'] else ''
)
)
),
name=user.get('name'),
amount=gp_details['amount'],
recurring=(
recurring_text
if gp_details['recurring'] else ''
)
)
),
'reply_to': ['info@ungleich.ch'],
}
send_plain_email_task.delay(email_data)

View file

@ -741,3 +741,22 @@ class StripeTaxRate(AssignPermissionsMixin, models.Model):
display_name = models.CharField(max_length=100)
percentage = models.FloatField(default=0)
description = models.CharField(max_length=100)
class IncompleteSubscriptions(AssignPermissionsMixin, models.Model):
created_at = models.DateTimeField(auto_now_add=True)
completed_at = models.DateTimeField()
subscription_id = models.CharField(max_length=100)
subscription_status = models.CharField(max_length=30)
name = models.CharField(max_length=50)
email = models.EmailField()
request = models.TextField()
stripe_api_cus_id = models.CharField(max_length=30)
card_details_response = models.TextField()
stripe_subscription_obj = models.TextField()
stripe_onetime_charge = models.TextField()
gp_details = models.TextField()
specs = models.TextField()
vm_template_id = models.PositiveIntegerField(default=0)
template = models.TextField()
billing_address_data = models.TextField()

View file

@ -1,7 +1,8 @@
import datetime
import logging
import json
import stripe
# Create your views here.
from django.conf import settings
from django.http import HttpResponse
@ -10,7 +11,7 @@ from django.views.decorators.http import require_POST
from datacenterlight.views import do_create_vm
from membership.models import StripeCustomer
from hosting.models import HostingOrder
from hosting.models import IncompleteSubscriptions
from utils.models import BillingAddress, UserBillingAddress
from utils.tasks import send_plain_email_task
@ -115,14 +116,16 @@ def handle_webhook(request):
}
send_plain_email_task.delay(email_data)
elif event.type == 'invoice.paid':
#https://stripe.com/docs/billing/migration/strong-customer-authentication#scenario-1-handling-fulfillment
#More info: https://stripe.com/docs/billing/migration/strong-customer-authentication#scenario-1-handling-fulfillment
invoice_obj = event.data.object
logger.debug("Webhook Event: invoice.paid")
logger.debug("invoice_obj %s " % str(invoice_obj))
logger.debug("invoice_obj.paid = %s %s" % (invoice_obj.paid, type(invoice_obj.paid)))
logger.debug("invoice_obj.billing_reason = %s %s" % (invoice_obj.billing_reason, type(invoice_obj.billing_reason)))
# We should check for billing_reason == "subscription_create" but we check for "subscription_update"
# because we are using older api. See https://stripe.com/docs/upgrades?since=2015-07-13
# We should check for billing_reason == "subscription_create" but we
# check for "subscription_update"
# because we are using older api.
# See https://stripe.com/docs/upgrades?since=2015-07-13
# The billing_reason attribute of the invoice object now can take the
# value of subscription_create, indicating that it is the first
@ -130,32 +133,54 @@ def handle_webhook(request):
# billing_reason=subscription_create is represented as
# subscription_update.
if invoice_obj.paid and invoice_obj.billing_reason == "subscription_update":
if (invoice_obj.paid and
invoice_obj.billing_reason == "subscription_update"):
logger.debug("Start provisioning")
# get subscription id, order_id
ho = None
try:
ho = HostingOrder.objects.get(subscription_id=invoice_obj.subscription)
stripe_subscription_obj = stripe.Subscription.retrieve(
invoice_obj.subscription)
try:
incomplete_sub = IncompleteSubscriptions.objects.get(
subscription_id=invoice_obj.subscription)
logger.debug("*******")
logger.debug(incomplete_sub)
logger.debug("*******")
do_create_vm(
request=incomplete_sub.request,
user={'name': incomplete_sub.name,
'email': incomplete_sub.email},
stripe_api_cus_id=incomplete_sub.stripe_api_cus_id,
card_details_response=json.loads(
incomplete_sub.card_details_response),
stripe_subscription_obj=json.loads(
stripe_subscription_obj),
stripe_onetime_charge=json.loads(
incomplete_sub.stripe_onetime_charge),
gp_details=json.loads(incomplete_sub.gp_details),
specs=json.loads(incomplete_sub.specs),
vm_template_id=incomplete_sub.vm_template_id,
template=json.loads(incomplete_sub.template)
)
except (IncompleteSubscriptions.DoesNotExist,
IncompleteSubscriptions.MultipleObjectsReturned) as ex:
logger.error(str(ex))
# TODO Inform admin
email_data = {
'subject': "IncompleteSubscriptions error",
'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
'to': settings.DCL_ERROR_EMAILS_TO_LIST,
'body': "Response = %s" % str(ex),
}
send_plain_email_task.delay(email_data)
except Exception as ex:
logger.error(str(ex))
if ho:
logger.debug("Create a VM for order %s" % str(ho))
# TODO: fix the error below
try:
user = {'name': ho.customer.user.name,
'email': ho.customer.user.email}
stripe_api_cus_id = ho.customer.stripe_id
stripe_subscription_obj = stripe.Subscription.retrieve(invoice_obj.subscription)
do_create_vm(request, user, stripe_api_cus_id,
card_details_response,
stripe_subscription_obj,
stripe_onetime_charge, gp_details, specs,
vm_template_id,
template
)
except Exception as ex:
logger.error(str(ex))
email_data = {
'subject': "invoice.paid Webhook error",
'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
'to': settings.DCL_ERROR_EMAILS_TO_LIST,
'body': "Response = %s" % str(ex),
}
send_plain_email_task.delay(email_data)
else:
logger.error("Unhandled event : " + event.type)
return HttpResponse(status=200)