Merge pull request #361 from pcoder/new_flow_enhancement

New flow enhancement
This commit is contained in:
Pcoder 2017-06-30 19:13:37 +02:00 committed by GitHub
commit 0ad3e0d7c7
5 changed files with 203 additions and 151 deletions

View file

@ -1,6 +1,7 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 %} {% load staticfiles bootstrap3 %}
{% load i18n %} {% load i18n %}
{% load custom_tags %}
{% block content %} {% block content %}
<div class="order-detail-container"> <div class="order-detail-container">
@ -20,22 +21,23 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-8 col-md-offset-2"> <div class="col-xs-12 col-md-8 col-md-offset-2">
<div class="invoice-title"> <div class="invoice-title">
<h2>{% trans "Confirm Order"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{order.id}}</h3> <h2>{% trans "Confirm Order"%}</h2>
</div> </div>
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">
<address> <address>
<h3><b>{% trans "Billed To:"%}</b></h3> <h3><b>{% trans "Billed To:"%}</b></h3>
{{user.name}}<br> {% with request.session.billing_address_data as billing_address %}
{{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br> {{request.session.user.name}}<br> {{billing_address|get_value_from_dict:'street_address'}}, {{billing_address|get_value_from_dict:'postal_code'}}<br>
{{order.billing_address.city}}, {{order.billing_address.country}}. {{billing_address|get_value_from_dict:'city'}}, {{billing_address|get_value_from_dict:'country'}}.
{% endwith %}
</address> </address>
</div> </div>
<div class="col-xs-6 text-right"> <div class="col-xs-6 text-right">
<address> <address>
<strong>{% trans "Date"%}:</strong><br> <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> </address>
</div> </div>
@ -44,8 +46,8 @@
<div class="col-xs-6"> <div class="col-xs-6">
<address> <address>
<strong>{% trans "Payment Method:"%}</strong><br> <strong>{% trans "Payment Method:"%}</strong><br>
{{order.cc_brand}} ending **** {{order.last4}}<br> {{cc_brand}} ending **** {{cc_last4}}<br>
{{user.email}} {{request.session.user.email}}
</address> </address>
</div> </div>
</div> </div>
@ -57,23 +59,37 @@
<h3><b>{% trans "Order summary"%}</b></h3> <h3><b>{% trans "Order summary"%}</b></h3>
<hr> <hr>
<div class="content"> <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> <hr>
<p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p> <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p>
<hr> <hr>
<p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p> <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p>
<hr> <hr>
<h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4> <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4>
{% endwith %}
</div> </div>
<br/> <br/>
{% url 'datacenterlight:payment' as payment_url %} <form method="post">
{% if payment_url in request.META.HTTP_REFERER %} {% csrf_token %}
<div class=" content pull-right"> <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> </div>
{% endif %} </form>
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </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%} {%endblock%}

View file

@ -22,3 +22,13 @@ def change_lang(context, lang=None, *args, **kwargs):
return "%s" % url 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 ""

View file

@ -9,7 +9,7 @@ urlpatterns = [
url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'), url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
url(r'^/pricing/?$', PricingView.as_view(), name='pricing'), url(r'^/pricing/?$', PricingView.as_view(), name='pricing'),
url(r'^/payment/?$', PaymentOrderView.as_view(), name='payment'), 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'^/order-success/?$', SuccessView.as_view(), name='order_success'),
url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'), url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'),
] ]

View file

@ -13,6 +13,7 @@ from django.core.exceptions import ValidationError
from django.views.decorators.cache import cache_control from django.views.decorators.cache import cache_control
from django.conf import settings from django.conf import settings
from utils.forms import BillingAddressForm, UserBillingAddressForm from utils.forms import BillingAddressForm, UserBillingAddressForm
from utils.models import BillingAddress
from membership.models import StripeCustomer from membership.models import StripeCustomer
from hosting.models import HostingOrder, HostingBill from hosting.models import HostingOrder, HostingBill
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
@ -31,9 +32,14 @@ class SuccessView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if 'specs' not in request.session or 'user' not in request.session: if 'specs' not in request.session or 'user' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:index')) return HttpResponseRedirect(reverse('datacenterlight:index'))
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: else:
del request.session['specs'] for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data', 'token', 'customer']:
del request.session['user'] if session_var in request.session:
del request.session[session_var]
return render(request, self.template_name) return render(request, self.template_name)
class PricingView(TemplateView): class PricingView(TemplateView):
@ -322,13 +328,9 @@ class PaymentOrderView(FormView):
if form.is_valid(): if form.is_valid():
# Get billing address data # Get billing address data
billing_address_data = form.cleaned_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') token = form.cleaned_data.get('token')
user = request.session.get('user')
try: try:
custom_user = CustomUser.objects.get(email=user.get('email')) custom_user = CustomUser.objects.get(email=user.get('email'))
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
@ -340,7 +342,6 @@ class PaymentOrderView(FormView):
app='dcl', app='dcl',
base_url=None, send_email=False) base_url=None, send_email=False)
# Get or create stripe customer # Get or create stripe customer
customer = StripeCustomer.get_or_create(email=user.get('email'), customer = StripeCustomer.get_or_create(email=user.get('email'),
token=token) token=token)
@ -350,6 +351,48 @@ class PaymentOrderView(FormView):
# Create Billing Address # Create Billing Address
billing_address = form.save() 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 # Make stripe charge to a customer
stripe_utils = StripeUtils() stripe_utils = StripeUtils()
@ -360,10 +403,11 @@ class PaymentOrderView(FormView):
# Check if the payment was approved # Check if the payment was approved
if not charge: if not charge:
context.update({ context.update({
'paymentError': charge_response.get('error'), 'paymentError': charge_response.get('error')
'form': form # 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') charge = charge_response.get('response_object')
@ -371,7 +415,7 @@ class PaymentOrderView(FormView):
manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME, manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
password=settings.OPENNEBULA_PASSWORD) password=settings.OPENNEBULA_PASSWORD)
# Create a vm using logged user # Create a vm using oneadmin, also specify the name
vm_id = manager.create_vm( vm_id = manager.create_vm(
template_id=vm_template_id, template_id=vm_template_id,
specs=specs, specs=specs,
@ -424,41 +468,13 @@ class PaymentOrderView(FormView):
'order.id': order.id 'order.id': order.id
} }
email_data = { email_data = {
'subject': "Data Center Light Order from %s" % context['email'], 'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
'from_email': '(Data Center Light) Data Center Light Support <support@datacenterlight.ch>', 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
'to': ['info@ungleich.ch'], 'to': ['info@ungleich.ch'],
'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]), 'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
'reply_to': [context['email']], 'reply_to': [context['email']],
} }
email = EmailMessage(**email_data) email = EmailMessage(**email_data)
email.send() email.send()
return HttpResponseRedirect(reverse('datacenterlight:order_confirmation', kwargs={'pk': order.id})) request.session['order_confirmation'] = True
else: return HttpResponseRedirect(reverse('datacenterlight:order_success'))
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

View file

@ -77,6 +77,16 @@ class StripeUtils(object):
} }
return new_card_data 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): def check_customer(self, id, user, token):
customers = self.stripe.Customer.all() customers = self.stripe.Customer.all()
if not customers.get('data'): if not customers.get('data'):