Merge branch 'master' into feature/add_google_analytics

# Conflicts:
#	datacenterlight/templates/datacenterlight/order_detail.html
This commit is contained in:
Andrii Marynets 2017-07-02 17:56:07 +03:00
commit 303d99d70d
10 changed files with 328 additions and 188 deletions

View file

@ -1,3 +1,11 @@
1.0.18: 2017-07-02
* [datacenterlight] Introduced the new flow. Landing page -> Payment -> Order confirmation -> Success
* [datacenterlight] Fixed issue showing local time to the user in order confirmation page, vm pages (like ssh keys)
* [hosting] Fixed responsive issue while user signup
* [hosting] Fixed 500 error when user requests for a vm whose id does not belong to him
* [datacenterlight] Refactored partially dcl text and dcl support email to be obtained from env parameters
* [datacenterlight] Updated DE translations
* [hosting] Updated email text for user activation
1.0.17: 2017-06-16 1.0.17: 2017-06-16
* [datacenterlight] Cleanup OrderView useless code * [datacenterlight] Cleanup OrderView useless code
* [datacenterlight] Replaced GiB to GB * [datacenterlight] Replaced GiB to GB
@ -5,7 +13,7 @@
* [datacenterlight] Fixed translations * [datacenterlight] Fixed translations
* [datacenterlight] Added email confirmation feature * [datacenterlight] Added email confirmation feature
* [datacenterlight] Changed logo on datacerlight dashboard * [datacenterlight] Changed logo on datacerlight dashboard
* [datacenterlight] Credit card input disappearance fix * [datacenterlight] Credit card input disappearance fix
1.0.16: 2017-06-15 1.0.16: 2017-06-15
* [datacenterlight] .po file issue with multiple definition fixed * [datacenterlight] .po file issue with multiple definition fixed
* [datacenterlight] Navbar items in dcl user area rearranged * [datacenterlight] Navbar items in dcl user area rearranged

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-19 12:22+0530\n" "POT-Creation-Date: 2017-07-01 02:15+0530\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -99,15 +99,18 @@ msgid ""
"datacenterlight account.<br/>\n" "datacenterlight account.<br/>\n"
" %(base_url)s%(activation_link)s\n" " %(base_url)s%(activation_link)s\n"
" " " "
msgstr "\n" msgstr ""
" <a href=\"%(base_url)s%(activation_link)s\">Klicke hier</a> um deinen %(dcl_text)s zu aktivieren.<br/><br/>\n" "\n"
" Oder kopiere den folgenden Link in die Adressleiste deines Browsers und folge dann dem Link um deinen %(dcl_text)s Account zu aktivieren.<br/>\n" " <a href=\"%(base_url)s%(activation_link)s\">Klicke hier</a> "
"um deinen %(dcl_text)s zu aktivieren.<br/><br/>\n"
" Oder kopiere den folgenden Link in die Adressleiste deines "
"Browsers und folge dann dem Link um deinen %(dcl_text)s Account zu "
"aktivieren.<br/>\n"
" %(base_url)s%(activation_link)s\n" " %(base_url)s%(activation_link)s\n"
" " " "
#: templates/datacenterlight/emails/user_activation.html:123 #: templates/datacenterlight/emails/user_activation.html:123
#: templates/datacenterlight/emails/user_activation.txt:11 #: templates/datacenterlight/emails/user_activation.txt:11
#| msgid "Your Name"
msgid "Your" msgid "Your"
msgstr "Dein" msgstr "Dein"
@ -128,8 +131,9 @@ msgstr ""
"\n" "\n"
"Hallo,\n" "Hallo,\n"
"\n" "\n"
"Du kannst deinen %(dcl_text)s Account aktivieren, indem du hier klickst %(base_url)s" "Du kannst deinen %(dcl_text)s Account aktivieren, indem du hier klickst "
"%(activation_link)s\n" "%(base_url)s%(activation_link)s\n"
#: templates/datacenterlight/includes/_footer.html:11 #: templates/datacenterlight/includes/_footer.html:11
#: templates/datacenterlight/includes/_footer.html:31 #: templates/datacenterlight/includes/_footer.html:31
#: templates/datacenterlight/includes/_navbar.html:27 #: templates/datacenterlight/includes/_navbar.html:27
@ -298,6 +302,54 @@ msgstr "Fragen?"
msgid "Contact us!" msgid "Contact us!"
msgstr "Kontaktiere uns!" msgstr "Kontaktiere uns!"
#: templates/datacenterlight/order_detail.html:24
msgid "Confirm Order"
msgstr "Bestellung Bestätigen"
#: templates/datacenterlight/order_detail.html:30
msgid "Billed To:"
msgstr "Rechnungsadresse"
#: templates/datacenterlight/order_detail.html:39
msgid "Date"
msgstr "Datum"
#: templates/datacenterlight/order_detail.html:48
msgid "Payment Method:"
msgstr "Bezahlmethode"
#: templates/datacenterlight/order_detail.html:49
msgid "ending"
msgstr "endend in"
#: templates/datacenterlight/order_detail.html:59
msgid "Order summary"
msgstr "Bestellungsübersicht"
#: templates/datacenterlight/order_detail.html:63
msgid "Cores"
msgstr "Prozessorkerne"
#: templates/datacenterlight/order_detail.html:65
msgid "Memory"
msgstr "Arbeitsspeicher"
#: templates/datacenterlight/order_detail.html:67
msgid "Disk space"
msgstr "Festplattenkapazität"
#: templates/datacenterlight/order_detail.html:69
msgid "Configuration"
msgstr "Konfiguration"
#: templates/datacenterlight/order_detail.html:71
msgid "Total"
msgstr ""
#: templates/datacenterlight/order_detail.html:78
msgid "Place order"
msgstr "Bestellen"
#: templates/datacenterlight/pricing.html:9 #: templates/datacenterlight/pricing.html:9
msgid "We are cutting down the costs significantly!" msgid "We are cutting down the costs significantly!"
msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen" msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen"

View file

@ -1,7 +1,9 @@
{% 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">
{% if messages %} {% if messages %}
<div class="row"> <div class="row">
@ -18,37 +20,38 @@
{% if not error %} {% if not error %}
<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'}}.
</address> {% endwith %}
</div> </address>
</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>
</div> </div>
<div class="row"> <div class="row">
<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}} {% trans "ending" %} **** {{cc_last4}}<br>
{{user.email}} {{request.session.user.email}}
</address> </address>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -56,23 +59,39 @@
<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 %}
<hr> <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cpu}}</span></p>
<p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p> <hr>
<hr> <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p>
<p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p> <hr>
<hr> <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p>
<h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4> <hr>
<p><b>{% trans "Configuration"%}</b> <span class="pull-right">{{request.session.template.name}}</span></p>
<hr>
<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

@ -21,4 +21,14 @@ def change_lang(context, lang=None, *args, **kwargs):
activate(cur_language) activate(cur_language)
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'))
else : elif 'token' not in request.session:
del request.session['specs'] return HttpResponseRedirect(reverse('datacenterlight:payment'))
del request.session['user'] 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) return render(request, self.template_name)
class PricingView(TemplateView): class PricingView(TemplateView):
@ -192,11 +198,13 @@ class IndexView(CreateView):
del request.session['specs'] del request.session['specs']
if 'user' in request.session : if 'user' in request.session :
del request.session['user'] del request.session['user']
if 'billing_address_data' in request.session :
del request.session['billing_address_data']
try: try:
manager = OpenNebulaManager() manager = OpenNebulaManager()
templates = manager.get_templates() templates = manager.get_templates()
context = { context = {
'templates': VirtualMachineTemplateSerializer(templates, many=True).data, 'templates': VirtualMachineTemplateSerializer(templates, many=True).data
} }
except: except:
messages.error( request, messages.error( request,
@ -303,11 +311,27 @@ class IndexView(CreateView):
class PaymentOrderView(FormView): class PaymentOrderView(FormView):
template_name = 'hosting/payment.html' template_name = 'hosting/payment.html'
form_class = BillingAddressForm form_class = BillingAddressForm
def get_form_kwargs(self):
form_kwargs = super(PaymentOrderView, self).get_form_kwargs()
billing_address_data = self.request.session.get('billing_address_data')
if billing_address_data:
form_kwargs.update({
'initial': {
'street_address': billing_address_data['street_address'],
'city': billing_address_data['city'],
'postal_code': billing_address_data['postal_code'],
'country': billing_address_data['country'],
}
})
return form_kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PaymentOrderView, self).get_context_data(**kwargs) context = super(PaymentOrderView, self).get_context_data(**kwargs)
context.update({ context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY 'stripe_key': settings.STRIPE_API_PUBLIC_KEY,
'site_url': reverse('datacenterlight:index')
}) })
return context return context
@ -322,13 +346,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 +360,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,115 +369,131 @@ 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
# Make stripe charge to a customer request.session['billing_address'] = billing_address.id
stripe_utils = StripeUtils() request.session['token'] = token
charge_response = stripe_utils.make_charge(amount=final_price, request.session['customer'] = customer.id
customer=customer.stripe_id) return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
charge = charge_response.get('response_object')
# Check if the payment was approved
if not charge:
context.update({
'paymentError': charge_response.get('error'),
'form': form
})
return render(request, self.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 logged user
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
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': "Data Center Light Order from %s" % context['email'],
'from_email': '(Data Center Light) Data Center Light Support <support@datacenterlight.ch>',
'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: else:
return self.form_invalid(form) return self.form_invalid(form)
class OrderConfirmationView(DetailView): class OrderConfirmationView(DetailView):
template_name = "datacenterlight/order_detail.html" template_name = "datacenterlight/order_detail.html"
payment_template_name = 'hosting/payment.html'
context_object_name = "order" context_object_name = "order"
model = HostingOrder model = HostingOrder
def get_context_data(self, **kwargs):
# Get context @cache_control(no_cache=True, must_revalidate=True, no_store=True)
context = super(DetailView, self).get_context_data(**kwargs) def get(self, request, *args, **kwargs):
obj = self.get_object() 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 = {
'site_url': reverse('datacenterlight:index'),
'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()
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.update({
'paymentError': charge_response.get('error')
# TODO add logic in payment form to autofill data
#'form': form
})
return render(request, self.payment_template_name, context)
charge = charge_response.get('response_object')
# Create OpenNebulaManager
manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME, manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
password=settings.OPENNEBULA_PASSWORD) password=settings.OPENNEBULA_PASSWORD)
try:
vm = manager.get_vm(obj.vm_id) # Create a vm using oneadmin, also specify the name
context['vm'] = VirtualMachineSerializer(vm).data vm_id = manager.create_vm(
context['next_url'] = reverse('datacenterlight:order_success') template_id=vm_template_id,
except WrongIdError: specs=specs,
messages.error(self.request, vm_name="{email}-{template_name}-{date}".format(
'The VM you are looking for is unavailable at the moment. \ email=user.get('email'),
Please contact Data Center Light support.' template_name=template.get('name'),
) date=int(datetime.now().strftime("%s")))
self.kwargs['error'] = 'WrongIdError' )
context['error'] = 'WrongIdError'
except ConnectionRefusedError: # Create a Hosting Order
messages.error(self.request, order = HostingOrder.create(
'In order to create a VM, you need to create/upload your SSH KEY first.' price=final_price,
) vm_id=vm_id,
return context customer=customer,
billing_address=billing_address
)
# Create a Hosting Bill
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': ['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()
request.session['order_confirmation'] = True
return HttpResponseRedirect(reverse('datacenterlight:order_success'))

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-23 02:28+0530\n" "POT-Creation-Date: 2017-07-01 02:09+0530\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -26,47 +26,47 @@ msgstr "Dein Account wurde noch nicht aktiviert."
msgid "Paste here your public key" msgid "Paste here your public key"
msgstr "Fügen Sie Ihren public key ein" msgstr "Fügen Sie Ihren public key ein"
#: templates/hosting/base_short.html:67 #: templates/hosting/base_short.html:68
msgid "My Virtual Machines" msgid "My Virtual Machines"
msgstr "Meine virtuellen Maschinen" msgstr "Meine virtuellen Maschinen"
#: templates/hosting/base_short.html:72 templates/hosting/orders.html.py:12 #: templates/hosting/base_short.html:73 templates/hosting/orders.html.py:12
msgid "My Orders" msgid "My Orders"
msgstr "Meine Bestellungen" msgstr "Meine Bestellungen"
#: templates/hosting/base_short.html:81 #: templates/hosting/base_short.html:82
msgid "Keys" msgid "Keys"
msgstr "Schlüssel" msgstr "Schlüssel"
#: templates/hosting/base_short.html:86 #: templates/hosting/base_short.html:87
msgid "Notifications " msgid "Notifications "
msgstr "Benachrichtigungen" msgstr "Benachrichtigungen"
#: templates/hosting/base_short.html:89 #: templates/hosting/base_short.html:90
msgid "Logout" msgid "Logout"
msgstr "Abmelden" msgstr "Abmelden"
#: templates/hosting/base_short.html:94 #: templates/hosting/base_short.html:95
msgid "How it works" msgid "How it works"
msgstr "So funktioniert es" msgstr "So funktioniert es"
#: templates/hosting/base_short.html:97 #: templates/hosting/base_short.html:98
msgid "Your infrastructure" msgid "Your infrastructure"
msgstr "deine Infrastruktur" msgstr "deine Infrastruktur"
#: templates/hosting/base_short.html:100 #: templates/hosting/base_short.html:101
msgid "Our inftrastructure" msgid "Our inftrastructure"
msgstr "Unsere Infrastruktur" msgstr "Unsere Infrastruktur"
#: templates/hosting/base_short.html:103 #: templates/hosting/base_short.html:104
msgid "Pricing" msgid "Pricing"
msgstr "Preise" msgstr "Preise"
#: templates/hosting/base_short.html:106 #: templates/hosting/base_short.html:107
msgid "Contact" msgid "Contact"
msgstr "Kontakt" msgstr "Kontakt"
#: templates/hosting/base_short.html:109 #: templates/hosting/base_short.html:110
#: templates/hosting/confirm_reset_password.html:38 #: templates/hosting/confirm_reset_password.html:38
#: templates/hosting/login.html:17 templates/hosting/login.html.py:26 #: templates/hosting/login.html:17 templates/hosting/login.html.py:26
#: templates/hosting/reset_password.html:32 templates/hosting/signup.html:30 #: templates/hosting/reset_password.html:32 templates/hosting/signup.html:30
@ -347,11 +347,11 @@ msgstr "Bestellung stornieren"
msgid "Do You want to delete your order?" msgid "Do You want to delete your order?"
msgstr "Willst du deine Bestellung löschen?" msgstr "Willst du deine Bestellung löschen?"
#: templates/hosting/orders.html:63 templates/hosting/user_keys.html.py:62 #: templates/hosting/orders.html:63 templates/hosting/user_keys.html.py:63
msgid "Close" msgid "Close"
msgstr "Schliessen" msgstr "Schliessen"
#: templates/hosting/orders.html:65 templates/hosting/user_keys.html.py:64 #: templates/hosting/orders.html:65 templates/hosting/user_keys.html.py:65
msgid "Delete" msgid "Delete"
msgstr "Löschen" msgstr "Löschen"
@ -359,31 +359,36 @@ msgstr "Löschen"
msgid "Billing Amount" msgid "Billing Amount"
msgstr "Rechnungsbetrag" msgstr "Rechnungsbetrag"
#: templates/hosting/payment.html:35 #: templates/hosting/payment.html:26
#: templates/hosting/virtual_machine_detail.html:98
msgid "Configuration"
msgstr "Konfiguration"
#: templates/hosting/payment.html:38
msgid "Billing Address" msgid "Billing Address"
msgstr "Rechnungsadresse" msgstr "Rechnungsadresse"
#: templates/hosting/payment.html:49 #: templates/hosting/payment.html:52
msgid "Payment Details" msgid "Payment Details"
msgstr "Rechnungsdetails" msgstr "Rechnungsdetails"
#: templates/hosting/payment.html:62 #: templates/hosting/payment.html:65
msgid "Submit Payment" msgid "Submit Payment"
msgstr "Betrag überweisen" msgstr "Betrag überweisen"
#: templates/hosting/payment.html:81 #: templates/hosting/payment.html:84
msgid "CARD NUMBER" msgid "CARD NUMBER"
msgstr "Kreditkartennummer" msgstr "Kreditkartennummer"
#: templates/hosting/payment.html:86 #: templates/hosting/payment.html:89
msgid "Valid Card Number" msgid "Valid Card Number"
msgstr "Gültige Kreditkartennummer" msgstr "Gültige Kreditkartennummer"
#: templates/hosting/payment.html:95 #: templates/hosting/payment.html:98
msgid "EXPIRATION DATE" msgid "EXPIRATION DATE"
msgstr "Ablaufdatum" msgstr "Ablaufdatum"
#: templates/hosting/payment.html:106 #: templates/hosting/payment.html:109
msgid "CV CODE" msgid "CV CODE"
msgstr "CV Code" msgstr "CV Code"
@ -425,13 +430,13 @@ msgstr "Schlüssel hinzufügen"
msgid "Created at" msgid "Created at"
msgstr "Erstellt am" msgstr "Erstellt am"
#: templates/hosting/user_keys.html:42 #: templates/hosting/user_keys.html:43
#, fuzzy #, fuzzy
#| msgid "Delete" #| msgid "Delete"
msgid "Delete Key" msgid "Delete Key"
msgstr "Löschen" msgstr "Löschen"
#: templates/hosting/user_keys.html:55 #: templates/hosting/user_keys.html:56
#, fuzzy #, fuzzy
#| msgid "Do You want do delete your order?" #| msgid "Do You want do delete your order?"
msgid "Do You want to delete this key?" msgid "Do You want to delete this key?"
@ -453,10 +458,6 @@ msgstr "Ip nicht zugewiesen"
msgid "Disk" msgid "Disk"
msgstr "Festplatte" msgstr "Festplatte"
#: templates/hosting/virtual_machine_detail.html:98
msgid "Configuration"
msgstr "Konfiguration"
#: templates/hosting/virtual_machine_detail.html:108 #: templates/hosting/virtual_machine_detail.html:108
msgid "Current pricing" msgid "Current pricing"
msgstr "Aktueller Preis" msgstr "Aktueller Preis"

View file

@ -57,7 +57,7 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand topnav" href="{{ request.session.hosting_url}}"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a> <a class="navbar-brand topnav" href="{% if site_url %}{{site_url}}{% else %}{{ request.session.hosting_url}}{% endif %}"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
</div> </div>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<!-- Collect the nav links, forms, and other content for toggling --> <!-- Collect the nav links, forms, and other content for toggling -->
@ -131,6 +131,8 @@
<p class="copyright text-muted small">Copyright &copy; ungleich GmbH {% now "Y" %}. All Rights Reserved</p> <p class="copyright text-muted small">Copyright &copy; ungleich GmbH {% now "Y" %}. All Rights Reserved</p>
</div> </div>
</footer> </footer>
{% else %}
{% include "datacenterlight/includes/_footer.html" %}
{% endif %} {% endif %}
<!-- jQuery --> <!-- jQuery -->
<script src="{% static 'hosting/js/jquery.js' %}"></script> <script src="{% static 'hosting/js/jquery.js' %}"></script>

View file

@ -22,6 +22,9 @@
<hr> <hr>
<p><b>{%trans "Disk space"%}</b> <span <p><b>{%trans "Disk space"%}</b> <span
class="pull-right">{{request.session.specs.disk_size|floatformat}} GB</span></p> class="pull-right">{{request.session.specs.disk_size|floatformat}} GB</span></p>
<hr>
<p><b>{%trans "Configuration"%}</b> <span
class="pull-right">{{request.session.template.name}}</span></p>
<hr> <hr>
<h4>Total<p <h4>Total<p
class="pull-right"><b>{{request.session.specs.price }} CHF</b></p></h4> class="pull-right"><b>{{request.session.specs.price }} CHF</b></p></h4>

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'):