def create_vm(billing_address_data, stripe_customer_id, specs, stripe_subscription_obj, card_details_dict, request, vm_template_id, template, user): billing_address = BillingAddress( cardholder_name=billing_address_data['cardholder_name'], street_address=billing_address_data['street_address'], city=billing_address_data['city'], postal_code=billing_address_data['postal_code'], country=billing_address_data['country']) billing_address.save() customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() vm_pricing = (VMPricing.get_vm_pricing_by_name( name=specs['pricing_name']) if 'pricing_name' in specs else VMPricing.get_default_pricing()) final_price = (specs.get('total_price') if 'total_price' in specs else specs.get('price')) # Create a Hosting Order with vm_id = 0, we shall set it later in # celery task once the VM instance is up and running order = HostingOrder.create(price=final_price, customer=customer, billing_address=billing_address, vm_pricing=vm_pricing) order_detail_obj, obj_created = OrderDetail.objects.get_or_create( vm_template=VMTemplate.objects.get( opennebula_vm_template_id=vm_template_id), cores=specs['cpu'], memory=specs['memory'], ssd_size=specs['disk_size']) order.order_detail = order_detail_obj order.save() # Create a Hosting Bill HostingBill.create(customer=customer, billing_address=billing_address) # Create Billing Address for User if he does not have one if not customer.user.billing_addresses.count(): billing_address_data.update({'user': customer.user.id}) billing_address_user_form = UserBillingAddressForm( billing_address_data) billing_address_user_form.is_valid() billing_address_user_form.save() # Associate the given stripe subscription with the order order.set_subscription_id(stripe_subscription_obj.id, card_details_dict) # Set order status approved order.set_approved() create_vm_task.delay(vm_template_id, user, specs, template, order.id) for session_var in [ 'specs', 'template', 'billing_address', 'billing_address_data', 'card_id', 'token', 'customer' ]: if session_var in request.session: del request.session[session_var]
def test_create_vm_task(self): """Tests the create vm task for monthly subscription This test is supposed to validate the proper execution of celery create_vm_task on production, as we have no other way to do this. """ # We create a VM from the first template available to DCL vm_template = VMTemplate.objects.all().first() template_data = VMTemplateSerializer(vm_template).data # The specs of VM that we want to create specs = {'cpu': 1, 'memory': 2, 'disk_size': 10, 'price': 15} stripe_customer = StripeCustomer.get_or_create( email=self.customer_email, token=self.token) card_details = self.stripe_utils.get_card_details( stripe_customer.stripe_id) card_details_dict = card_details.get('error') self.assertEquals(card_details_dict, None) billing_address_data = { 'cardholder_name': self.customer_name, 'postal_code': '1231', 'country': 'CH', 'token': self.token, 'street_address': 'Monty\'s Street', 'city': 'Hollywood' } vm_template_id = template_data.get('id', 1) cpu = specs.get('cpu') memory = specs.get('memory') disk_size = specs.get('disk_size') amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, disk_size=disk_size) plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, memory=memory, disk_size=disk_size) stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu, ram=memory, ssd=disk_size, version=1, app='dcl') stripe_plan = self.stripe_utils.get_or_create_stripe_plan( amount=amount_to_be_charged, name=plan_name, stripe_plan_id=stripe_plan_id) subscription_result = self.stripe_utils.subscribe_customer_to_plan( stripe_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': msg = subscription_result.get('error') raise Exception("Creating subscription failed: {}".format(msg)) billing_address = BillingAddress( cardholder_name=billing_address_data['cardholder_name'], street_address=billing_address_data['street_address'], city=billing_address_data['city'], postal_code=billing_address_data['postal_code'], country=billing_address_data['country']) billing_address.save() order = HostingOrder.create(price=specs['price'], vm_id=0, customer=stripe_customer, billing_address=billing_address) async_task = create_vm_task.delay(vm_template_id, self.user, specs, template_data, order.id) new_vm_id = 0 res = None for i in range(0, 10): sleep(5) res = AsyncResult(async_task.task_id) if res.result is not None and res.result > 0: new_vm_id = res.result break # We expect a VM to be created within 50 seconds self.assertGreater( new_vm_id, 0, "VM could not be created. res._get_task_meta() = {}".format( res._get_task_meta()))
def post(self, request, *args, **kwargs): template = request.session.get('template') specs = request.session.get('specs') user = request.session.get('user') stripe_customer_id = request.session.get('customer') customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() billing_address_data = request.session.get('billing_address_data') billing_address_id = request.session.get('billing_address') billing_address = BillingAddress.objects.filter( id=billing_address_id).first() vm_template_id = template.get('id', 1) final_price = specs.get('price') # Make stripe charge to a customer stripe_utils = StripeUtils() charge_response = stripe_utils.make_charge(amount=final_price, customer=customer.stripe_id) charge = charge_response.get('response_object') # Check if the payment was approved if not charge: context = {} context.update({'paymentError': charge_response.get('error')}) return render(request, self.payment_template_name, context) charge = charge_response.get('response_object') # Create OpenNebulaManager manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME, password=settings.OPENNEBULA_PASSWORD) # Create a vm using oneadmin, also specify the name vm_id = manager.create_vm( template_id=vm_template_id, specs=specs, vm_name="{email}-{template_name}-{date}".format( email=user.get('email'), template_name=template.get('name'), date=int(datetime.now().strftime("%s")))) # Create a Hosting Order order = HostingOrder.create(price=final_price, vm_id=vm_id, customer=customer, billing_address=billing_address) # Create a Hosting Bill HostingBill.create(customer=customer, billing_address=billing_address) # Create Billing Address for User if he does not have one if not customer.user.billing_addresses.count(): billing_address_data.update({'user': customer.user.id}) billing_address_user_form = UserBillingAddressForm( billing_address_data) billing_address_user_form.is_valid() billing_address_user_form.save() # Associate an order with a stripe payment order.set_stripe_charge(charge) # If the Stripe payment was successed, set order status approved order.set_approved() vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data context = { 'name': user.get('name'), 'email': user.get('email'), 'cores': specs.get('cpu'), 'memory': specs.get('memory'), 'storage': specs.get('disk_size'), 'price': specs.get('price'), 'template': template.get('name'), 'vm.name': vm['name'], 'vm.id': vm['vm_id'], 'order.id': order.id } email_data = { 'subject': settings.DCL_TEXT + " Order from %s" % context['email'], 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, 'to': ['*****@*****.**'], 'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]), 'reply_to': [context['email']], } email = EmailMessage(**email_data) email.send() request.session['order_confirmation'] = True return HttpResponseRedirect(reverse('datacenterlight:order_success'))
def post(self, request, *args, **kwargs): user = request.session.get('user') stripe_api_cus_id = request.session.get('customer') stripe_utils = StripeUtils() if 'token' in request.session: card_details = stripe_utils.get_cards_details_from_token( request.session.get('token')) if not card_details.get('response_object'): msg = card_details.get('error') messages.add_message(self.request, messages.ERROR, msg, extra_tags='failed_payment') response = { 'status': False, 'redirect': "{url}#{section}".format( url=(reverse( 'show_product', kwargs={ 'product_slug': request.session['generic_payment_details'] ['product_slug'] }) if 'generic_payment_details' in request.session else reverse('datacenterlight:payment')), section='payment_error'), 'msg_title': str(_('Error.')), 'msg_body': str( _('There was a payment related error.' ' On close of this popup, you will be' ' redirected back to the payment page.')) } return JsonResponse(response) card_details_response = card_details['response_object'] card_details_dict = { 'last4': card_details_response['last4'], 'brand': card_details_response['brand'], 'card_id': card_details_response['card_id'] } stripe_customer_obj = StripeCustomer.objects.filter( stripe_id=stripe_api_cus_id).first() if stripe_customer_obj: ucd = UserCardDetail.get_user_card_details( stripe_customer_obj, card_details_response) if not ucd: acc_result = stripe_utils.associate_customer_card( stripe_api_cus_id, request.session['token'], set_as_default=True) if acc_result['response_object'] is None: msg = _('An error occurred while associating the card.' ' Details: {details}'.format( details=acc_result['error'])) messages.add_message(self.request, messages.ERROR, msg, extra_tags='failed_payment') response = { 'status': False, 'redirect': "{url}#{section}". format(url=(reverse( 'show_product', kwargs={ 'product_slug': request.session['generic_payment_details'] ['product_slug'] }) if 'generic_payment_details' in request.session else reverse('datacenterlight:payment')), section='payment_error'), 'msg_title': str(_('Error.')), 'msg_body': str( _('There was a payment related error.' ' On close of this popup, you will be redirected' ' back to the payment page.')) } return JsonResponse(response) elif 'card_id' in request.session: card_id = request.session.get('card_id') user_card_detail = UserCardDetail.objects.get(id=card_id) card_details_dict = { 'last4': user_card_detail.last4, 'brand': user_card_detail.brand, 'card_id': user_card_detail.card_id } else: response = { 'status': False, 'redirect': "{url}#{section}".format( url=reverse('datacenterlight:payment'), section='payment_error'), 'msg_title': str(_('Error.')), 'msg_body': str( _('There was a payment related error.' ' On close of this popup, you will be redirected back to' ' the payment page.')) } return JsonResponse(response) if ('generic_payment_type' in request.session and self.request.session['generic_payment_type'] == 'generic'): gp_details = self.request.session['generic_payment_details'] if gp_details['recurring']: # generic recurring payment logger.debug("Commencing a generic recurring payment") else: # generic one time payment logger.debug("Commencing a one time payment") charge_response = stripe_utils.make_charge( amount=gp_details['amount'], customer=stripe_api_cus_id) stripe_onetime_charge = charge_response.get('response_object') # Check if the payment was approved if not stripe_onetime_charge: msg = charge_response.get('error') messages.add_message(self.request, messages.ERROR, msg, extra_tags='failed_payment') response = { 'status': False, 'redirect': "{url}#{section}".format( url=(reverse('show_product', kwargs={ 'product_slug': gp_details['product_slug'] }) if 'generic_payment_details' in request.session else reverse('datacenterlight:payment')), section='payment_error'), 'msg_title': str(_('Error.')), 'msg_body': str( _('There was a payment related error.' ' On close of this popup, you will be redirected' ' back to the payment page.')) } return JsonResponse(response) if ('generic_payment_type' not in request.session or (request.session['generic_payment_details']['recurring'])): if 'generic_payment_details' in request.session: amount_to_be_charged = (round( request.session['generic_payment_details']['amount'], 2)) plan_name = "generic-{0}-{1:.2f}".format( request.session['generic_payment_details']['product_id'], amount_to_be_charged) stripe_plan_id = plan_name else: template = request.session.get('template') specs = request.session.get('specs') vm_template_id = template.get('id', 1) cpu = specs.get('cpu') memory = specs.get('memory') disk_size = specs.get('disk_size') amount_to_be_charged = specs.get('total_price') plan_name = StripeUtils.get_stripe_plan_name( cpu=cpu, memory=memory, disk_size=disk_size, price=amount_to_be_charged) stripe_plan_id = StripeUtils.get_stripe_plan_id( cpu=cpu, ram=memory, ssd=disk_size, version=1, app='dcl', price=amount_to_be_charged) stripe_plan = stripe_utils.get_or_create_stripe_plan( amount=amount_to_be_charged, name=plan_name, stripe_plan_id=stripe_plan_id) subscription_result = stripe_utils.subscribe_customer_to_plan( stripe_api_cus_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'): # At this point, we have created a Stripe API card and # associated it with the customer; but the transaction failed # due to some reason. So, we would want to dissociate this card # here. # ... msg = subscription_result.get('error') messages.add_message(self.request, messages.ERROR, msg, extra_tags='failed_payment') response = { 'status': False, 'redirect': "{url}#{section}".format( url=(reverse( 'show_product', kwargs={ 'product_slug': request.session['generic_payment_details'] ['product_slug'] }) if 'generic_payment_details' in request.session else reverse('datacenterlight:payment')), section='payment_error'), 'msg_title': str(_('Error.')), 'msg_body': str( _('There was a payment related error.' ' On close of this popup, you will be redirected back to' ' the payment page.')) } return JsonResponse(response) # Create user if the user is not logged in and if he is not already # registered if not request.user.is_authenticated(): try: custom_user = CustomUser.objects.get(email=user.get('email')) stripe_customer = StripeCustomer.objects.filter( user_id=custom_user.id).first() if stripe_customer is None: stripe_customer = StripeCustomer.objects.create( user=custom_user, stripe_id=stripe_api_cus_id) stripe_customer_id = stripe_customer.id except CustomUser.DoesNotExist: logger.debug("Customer {} does not exist.".format( user.get('email'))) password = CustomUser.get_random_password() base_url = "{0}://{1}".format(self.request.scheme, self.request.get_host()) custom_user = CustomUser.register(user.get('name'), password, user.get('email'), app='dcl', base_url=base_url, send_email=True, account_details=password) logger.debug("Created user {}.".format(user.get('email'))) stripe_customer = StripeCustomer.objects. \ create(user=custom_user, stripe_id=stripe_api_cus_id) stripe_customer_id = stripe_customer.id new_user = authenticate(username=custom_user.email, password=password) login(request, new_user) else: # We assume that if the user is here, his/her StripeCustomer # object already exists stripe_customer_id = request.user.stripecustomer.id custom_user = request.user if 'token' in request.session: ucd = UserCardDetail.get_or_create_user_card_detail( stripe_customer=self.request.user.stripecustomer, card_details=card_details_response) UserCardDetail.save_default_card_local( self.request.user.stripecustomer.stripe_id, ucd.card_id) else: card_id = request.session.get('card_id') user_card_detail = UserCardDetail.objects.get(id=card_id) card_details_dict = { 'last4': user_card_detail.last4, 'brand': user_card_detail.brand, 'card_id': user_card_detail.card_id } if not user_card_detail.preferred: UserCardDetail.set_default_card( stripe_api_cus_id=stripe_api_cus_id, stripe_source_id=user_card_detail.card_id) # Save billing address billing_address_data = request.session.get('billing_address_data') logger.debug('billing_address_data is {}'.format(billing_address_data)) billing_address_data.update({'user': custom_user.id}) if 'generic_payment_type' in request.session: stripe_cus = StripeCustomer.objects.filter( stripe_id=stripe_api_cus_id).first() billing_address = BillingAddress( cardholder_name=billing_address_data['cardholder_name'], street_address=billing_address_data['street_address'], city=billing_address_data['city'], postal_code=billing_address_data['postal_code'], country=billing_address_data['country']) billing_address.save() order = HostingOrder.create( price=self.request.session['generic_payment_details'] ['amount'], customer=stripe_cus, billing_address=billing_address, vm_pricing=VMPricing.get_default_pricing()) # Create a Hosting Bill HostingBill.create(customer=stripe_cus, billing_address=billing_address) # Create Billing Address for User if he does not have one if not stripe_cus.user.billing_addresses.count(): billing_address_data.update({'user': stripe_cus.user.id}) billing_address_user_form = UserBillingAddressForm( billing_address_data) billing_address_user_form.is_valid() billing_address_user_form.save() if self.request.session['generic_payment_details']['recurring']: # Associate the given stripe subscription with the order order.set_subscription_id(stripe_subscription_obj.id, card_details_dict) else: # Associate the given stripe charge id with the order order.set_stripe_charge(stripe_onetime_charge) # Set order status approved order.set_approved() order.generic_payment_description = gp_details["description"] order.generic_product_id = gp_details["product_id"] order.save() # send emails context = { 'name': user.get('name'), 'email': user.get('email'), 'amount': gp_details['amount'], 'description': gp_details['description'], 'recurring': gp_details['recurring'], 'product_name': gp_details['product_name'], 'product_id': gp_details['product_id'], 'order_id': order.id } email_data = { 'subject': (settings.DCL_TEXT + " Payment received from %s" % context['email']), 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, 'to': ['*****@*****.**'], 'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]), 'reply_to': [context['email']], } send_plain_email_task.delay(email_data) email_data = { 'subject': _("Confirmation of your payment"), 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, 'to': [user.get('email')], 'body': _("Hi {name},\n\n" "thank you for your order!\n" "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=(_(' This is a monthly recurring plan.') if gp_details['recurring'] else ''))), 'reply_to': ['*****@*****.**'], } send_plain_email_task.delay(email_data) response = { 'status': True, 'redirect': (reverse('hosting:orders') if request.user.is_authenticated() else reverse('datacenterlight:index')), 'msg_title': str(_('Thank you for the payment.')), 'msg_body': str( _('You will soon receive a confirmation email of the ' 'payment. You can always contact us at ' '[email protected] for any question that you may have.')) } clear_all_session_vars(request) return JsonResponse(response) user = { 'name': custom_user.name, 'email': custom_user.email, 'pass': custom_user.password, 'request_scheme': request.scheme, 'request_host': request.get_host(), 'language': get_language(), } create_vm(billing_address_data, stripe_customer_id, specs, stripe_subscription_obj, card_details_dict, request, vm_template_id, template, user) response = { 'status': True, 'redirect': (reverse('hosting:virtual_machines') if request.user.is_authenticated() else reverse('datacenterlight:index')), 'msg_title': str(_('Thank you for the order.')), 'msg_body': str( _('Your VM will be up and running in a few moments.' ' We will send you a confirmation email as soon as' ' it is ready.')) } return JsonResponse(response)