Handle IncompleteSubscriptions in webhook
This commit is contained in:
		
					parent
					
						
							
								c4c918d591
							
						
					
				
			
			
				commit
				
					
						17c8f9ca18
					
				
			
		
					 3 changed files with 130 additions and 60 deletions
				
			
		|  | @ -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) | ||||
|  |  | |||
|  | @ -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() | ||||
|  | @ -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) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue