Merge pull request #361 from pcoder/new_flow_enhancement
New flow enhancement
This commit is contained in:
		
				commit
				
					
						0ad3e0d7c7
					
				
			
		
					 5 changed files with 203 additions and 151 deletions
				
			
		| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
{% extends "hosting/base_short.html" %}
 | 
			
		||||
{% load staticfiles bootstrap3 %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load custom_tags %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
 | 
			
		||||
<div class="order-detail-container">
 | 
			
		||||
| 
						 | 
				
			
			@ -20,22 +21,23 @@
 | 
			
		|||
    <div class="row">  
 | 
			
		||||
        <div class="col-xs-12 col-md-8 col-md-offset-2">
 | 
			
		||||
            <div class="invoice-title">
 | 
			
		||||
    			<h2>{% trans "Confirm Order"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{order.id}}</h3>
 | 
			
		||||
                <h2>{% trans "Confirm Order"%}</h2>
 | 
			
		||||
            </div>
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-xs-6">
 | 
			
		||||
                    <address>
 | 
			
		||||
                    <h3><b>{% trans "Billed To:"%}</b></h3>
 | 
			
		||||
    					{{user.name}}<br>
 | 
			
		||||
                        {{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br>
 | 
			
		||||
                        {{order.billing_address.city}}, {{order.billing_address.country}}.
 | 
			
		||||
                    {% with request.session.billing_address_data as billing_address %}
 | 
			
		||||
                        {{request.session.user.name}}<br> {{billing_address|get_value_from_dict:'street_address'}}, {{billing_address|get_value_from_dict:'postal_code'}}<br>
 | 
			
		||||
                        {{billing_address|get_value_from_dict:'city'}}, {{billing_address|get_value_from_dict:'country'}}.
 | 
			
		||||
                    {% endwith %}
 | 
			
		||||
                    </address>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-xs-6 text-right">
 | 
			
		||||
                    <address>
 | 
			
		||||
                        <strong>{% trans "Date"%}:</strong><br>
 | 
			
		||||
                        {{order.created_at}}<br><br>
 | 
			
		||||
                        <span id="order-created_at">{% now "Y-m-d H:i" %}</span><br><br>
 | 
			
		||||
                    </address>
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +46,8 @@
 | 
			
		|||
                <div class="col-xs-6">
 | 
			
		||||
                    <address>
 | 
			
		||||
                        <strong>{% trans "Payment Method:"%}</strong><br>
 | 
			
		||||
    					{{order.cc_brand}} ending **** {{order.last4}}<br>
 | 
			
		||||
    					{{user.email}}
 | 
			
		||||
                            {{cc_brand}} ending **** {{cc_last4}}<br>
 | 
			
		||||
                            {{request.session.user.email}}
 | 
			
		||||
                    </address>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -57,23 +59,37 @@
 | 
			
		|||
            <h3><b>{% trans "Order summary"%}</b></h3>
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div class="content">
 | 
			
		||||
                <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cores}}</span></p>
 | 
			
		||||
                {% with request.session.specs as vm %}
 | 
			
		||||
                    <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cpu}}</span></p>
 | 
			
		||||
                    <hr>
 | 
			
		||||
                    <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p>
 | 
			
		||||
                    <hr>
 | 
			
		||||
                    <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p>
 | 
			
		||||
                    <hr>
 | 
			
		||||
                    <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4>
 | 
			
		||||
                {% endwith %}
 | 
			
		||||
            </div>
 | 
			
		||||
            <br/>
 | 
			
		||||
            {% url 'datacenterlight:payment' as payment_url %}
 | 
			
		||||
            {% if payment_url in request.META.HTTP_REFERER  %}
 | 
			
		||||
            <form method="post">
 | 
			
		||||
            {% csrf_token %}
 | 
			
		||||
            <div class=" content pull-right">
 | 
			
		||||
                <a href="{{next_url}}" ><button class="btn btn-info">{% trans "Finish Configuration"%}</button></a>
 | 
			
		||||
                <a href="{{next_url}}" ><button class="btn btn-info">{% trans "Place order"%}</button></a>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
<script type="text/javascript"> 
 | 
			
		||||
 | 
			
		||||
    window.onload = function () {
 | 
			
		||||
            var locale_date = moment.utc(document.getElementById("order-created_at").textContent,'YYYY-MM-DD HH:mm').toDate();
 | 
			
		||||
            locale_date =  moment(locale_date).format("YYYY-MM-DD h:mm:ss a");
 | 
			
		||||
            document.getElementById('order-created_at').innerHTML = locale_date;
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
{%endblock%}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,3 +22,13 @@ def change_lang(context, lang=None, *args, **kwargs):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    return "%s" % url
 | 
			
		||||
 | 
			
		||||
@register.filter('get_value_from_dict')
 | 
			
		||||
def get_value_from_dict(dict_data, key):
 | 
			
		||||
    """
 | 
			
		||||
    usage example {{ your_dict|get_value_from_dict:your_key }}
 | 
			
		||||
    """
 | 
			
		||||
    if key:
 | 
			
		||||
        return dict_data.get(key)
 | 
			
		||||
    else :
 | 
			
		||||
        return ""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ urlpatterns = [
 | 
			
		|||
    url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
 | 
			
		||||
    url(r'^/pricing/?$', PricingView.as_view(), name='pricing'),
 | 
			
		||||
    url(r'^/payment/?$', PaymentOrderView.as_view(), name='payment'),
 | 
			
		||||
    url(r'^/order-confirmation/(?P<pk>\d+)/?$', OrderConfirmationView.as_view(), name='order_confirmation'),
 | 
			
		||||
    url(r'^/order-confirmation/?$', OrderConfirmationView.as_view(), name='order_confirmation'),
 | 
			
		||||
    url(r'^/order-success/?$', SuccessView.as_view(), name='order_success'),
 | 
			
		||||
    url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'),
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ from django.core.exceptions import ValidationError
 | 
			
		|||
from django.views.decorators.cache import cache_control
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from utils.forms import BillingAddressForm, UserBillingAddressForm
 | 
			
		||||
from utils.models import BillingAddress
 | 
			
		||||
from membership.models import StripeCustomer
 | 
			
		||||
from hosting.models import HostingOrder, HostingBill
 | 
			
		||||
from utils.stripe_utils import StripeUtils
 | 
			
		||||
| 
						 | 
				
			
			@ -31,9 +32,14 @@ class SuccessView(TemplateView):
 | 
			
		|||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        if 'specs' not in request.session or 'user' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index'))
 | 
			
		||||
        else :
 | 
			
		||||
            del request.session['specs']
 | 
			
		||||
            del request.session['user']
 | 
			
		||||
        elif 'token' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:payment'))            
 | 
			
		||||
        elif 'order_confirmation' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))            
 | 
			
		||||
        else:
 | 
			
		||||
            for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data', 'token', 'customer']:
 | 
			
		||||
                if session_var in request.session:
 | 
			
		||||
                    del request.session[session_var]
 | 
			
		||||
        return render(request, self.template_name)
 | 
			
		||||
 | 
			
		||||
class PricingView(TemplateView):
 | 
			
		||||
| 
						 | 
				
			
			@ -322,13 +328,9 @@ class PaymentOrderView(FormView):
 | 
			
		|||
        if form.is_valid():
 | 
			
		||||
            # Get billing address data
 | 
			
		||||
            billing_address_data = form.cleaned_data
 | 
			
		||||
            context = self.get_context_data()
 | 
			
		||||
            template = request.session.get('template')
 | 
			
		||||
            specs = request.session.get('specs')
 | 
			
		||||
            user = request.session.get('user')
 | 
			
		||||
            vm_template_id = template.get('id', 1)
 | 
			
		||||
            final_price = specs.get('price')
 | 
			
		||||
            token = form.cleaned_data.get('token')
 | 
			
		||||
            user = request.session.get('user')
 | 
			
		||||
            
 | 
			
		||||
            try:
 | 
			
		||||
                custom_user = CustomUser.objects.get(email=user.get('email'))
 | 
			
		||||
            except CustomUser.DoesNotExist:
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +342,6 @@ class PaymentOrderView(FormView):
 | 
			
		|||
                                    app='dcl', 
 | 
			
		||||
                                    base_url=None, send_email=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            # Get or create stripe customer
 | 
			
		||||
            customer = StripeCustomer.get_or_create(email=user.get('email'),
 | 
			
		||||
                                                    token=token)
 | 
			
		||||
| 
						 | 
				
			
			@ -350,6 +351,48 @@ class PaymentOrderView(FormView):
 | 
			
		|||
 | 
			
		||||
            # Create Billing Address
 | 
			
		||||
            billing_address = form.save()
 | 
			
		||||
            request.session['billing_address_data'] = billing_address_data
 | 
			
		||||
            request.session['billing_address'] = billing_address.id
 | 
			
		||||
            request.session['token'] = token
 | 
			
		||||
            request.session['customer'] = customer.id
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
 | 
			
		||||
        else:
 | 
			
		||||
            return self.form_invalid(form)
 | 
			
		||||
 | 
			
		||||
class OrderConfirmationView(DetailView):
 | 
			
		||||
    template_name = "datacenterlight/order_detail.html"
 | 
			
		||||
    payment_template_name = 'hosting/payment.html'
 | 
			
		||||
    context_object_name = "order"
 | 
			
		||||
    model = HostingOrder
 | 
			
		||||
    
 | 
			
		||||
    @cache_control(no_cache=True, must_revalidate=True, no_store=True)
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        if 'specs' not in request.session or 'user' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index'))
 | 
			
		||||
        if 'token' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:payment'))
 | 
			
		||||
        stripe_customer_id = request.session.get('customer')
 | 
			
		||||
        customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
 | 
			
		||||
        stripe_utils = StripeUtils()
 | 
			
		||||
        card_details = stripe_utils.get_card_details(customer.stripe_id, request.session.get('token'))
 | 
			
		||||
        context = {
 | 
			
		||||
            'cc_last4' : card_details.get('response_object').get('last4'),
 | 
			
		||||
            'cc_brand' : card_details.get('response_object').get('brand')
 | 
			
		||||
        }
 | 
			
		||||
        return render(request, self.template_name, context)
 | 
			
		||||
   
 | 
			
		||||
    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()
 | 
			
		||||
        token = request.session.get('token')
 | 
			
		||||
        vm_template_id = template.get('id', 1)
 | 
			
		||||
        final_price = specs.get('price')
 | 
			
		||||
 | 
			
		||||
        # Make stripe charge to a customer
 | 
			
		||||
        stripe_utils = StripeUtils()
 | 
			
		||||
| 
						 | 
				
			
			@ -360,10 +403,11 @@ class PaymentOrderView(FormView):
 | 
			
		|||
        # Check if the payment was approved
 | 
			
		||||
        if not charge:
 | 
			
		||||
            context.update({
 | 
			
		||||
                    'paymentError': charge_response.get('error'),
 | 
			
		||||
                    'form': form
 | 
			
		||||
                'paymentError': charge_response.get('error')
 | 
			
		||||
                # TODO add logic in payment form to autofill data 
 | 
			
		||||
                #'form': form
 | 
			
		||||
            })
 | 
			
		||||
                return render(request, self.template_name, context)
 | 
			
		||||
            return render(request, self.payment_template_name, context)
 | 
			
		||||
 | 
			
		||||
        charge = charge_response.get('response_object')
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -371,7 +415,7 @@ class PaymentOrderView(FormView):
 | 
			
		|||
        manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
 | 
			
		||||
                                    password=settings.OPENNEBULA_PASSWORD)
 | 
			
		||||
        
 | 
			
		||||
            # Create a vm using logged user
 | 
			
		||||
        # Create a vm using oneadmin, also specify the name
 | 
			
		||||
        vm_id = manager.create_vm(
 | 
			
		||||
            template_id=vm_template_id,
 | 
			
		||||
            specs=specs,
 | 
			
		||||
| 
						 | 
				
			
			@ -424,41 +468,13 @@ class PaymentOrderView(FormView):
 | 
			
		|||
            'order.id': order.id
 | 
			
		||||
        }
 | 
			
		||||
        email_data = {
 | 
			
		||||
                'subject': "Data Center Light Order from %s" % context['email'],
 | 
			
		||||
                'from_email': '(Data Center Light) Data Center Light Support <support@datacenterlight.ch>',
 | 
			
		||||
            'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
 | 
			
		||||
            'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
 | 
			
		||||
            'to': ['info@ungleich.ch'],
 | 
			
		||||
            'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
 | 
			
		||||
            'reply_to': [context['email']],
 | 
			
		||||
        }
 | 
			
		||||
        email = EmailMessage(**email_data)
 | 
			
		||||
        email.send()
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:order_confirmation', kwargs={'pk': order.id}))
 | 
			
		||||
        else:
 | 
			
		||||
            return self.form_invalid(form)
 | 
			
		||||
 | 
			
		||||
class OrderConfirmationView(DetailView):
 | 
			
		||||
    template_name = "datacenterlight/order_detail.html"
 | 
			
		||||
    context_object_name = "order"
 | 
			
		||||
    model = HostingOrder
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        # Get context
 | 
			
		||||
        context = super(DetailView, self).get_context_data(**kwargs)
 | 
			
		||||
        obj = self.get_object()
 | 
			
		||||
        manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
 | 
			
		||||
                                    password=settings.OPENNEBULA_PASSWORD)
 | 
			
		||||
        try:
 | 
			
		||||
            vm = manager.get_vm(obj.vm_id)
 | 
			
		||||
            context['vm'] = VirtualMachineSerializer(vm).data
 | 
			
		||||
            context['next_url'] = reverse('datacenterlight:order_success')
 | 
			
		||||
        except WrongIdError:
 | 
			
		||||
            messages.error(self.request,
 | 
			
		||||
                           'The VM you are looking for is unavailable at the moment. \
 | 
			
		||||
                            Please contact Data Center Light support.'
 | 
			
		||||
                           )
 | 
			
		||||
            self.kwargs['error'] = 'WrongIdError'
 | 
			
		||||
            context['error'] = 'WrongIdError'
 | 
			
		||||
        except ConnectionRefusedError:
 | 
			
		||||
            messages.error(self.request,
 | 
			
		||||
                           'In order to create a VM, you need to create/upload your SSH KEY first.'
 | 
			
		||||
                           )
 | 
			
		||||
        return context
 | 
			
		||||
        request.session['order_confirmation'] = True
 | 
			
		||||
        return HttpResponseRedirect(reverse('datacenterlight:order_success'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,16 @@ class StripeUtils(object):
 | 
			
		|||
        }
 | 
			
		||||
        return new_card_data
 | 
			
		||||
 | 
			
		||||
    @handleStripeError
 | 
			
		||||
    def get_card_details(self, customer_id, token):
 | 
			
		||||
        customer = stripe.Customer.retrieve(customer_id)
 | 
			
		||||
        credit_card_raw_data = customer.sources.data.pop()
 | 
			
		||||
        card_details = {
 | 
			
		||||
            'last4': credit_card_raw_data.last4,
 | 
			
		||||
            'brand': credit_card_raw_data.brand
 | 
			
		||||
        }
 | 
			
		||||
        return card_details
 | 
			
		||||
 | 
			
		||||
    def check_customer(self, id, user, token):
 | 
			
		||||
        customers = self.stripe.Customer.all()
 | 
			
		||||
        if not customers.get('data'):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue