Merge master into task/3934/move_hosting_order_out_of_celery_task

and resolve some conflicts
This commit is contained in:
M.Ravi 2018-06-27 12:08:48 +02:00
commit 2cd73b313a
45 changed files with 1148 additions and 674 deletions

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-21 00:23+0000\n"
"POT-Creation-Date: 2018-05-12 03:53+0530\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -365,15 +365,24 @@ msgstr "Arbeitsspeicher"
msgid "Disk space"
msgstr "Festplattenkapazität"
msgid "Subtotal"
msgstr "Zwischensumme"
msgid "VAT"
msgstr "Mehrwertsteuer"
msgid "Discount"
msgstr "Rabatt"
msgid "Total"
msgstr "Gesamt"
#, python-format
msgid ""
"By clicking \"Place order\" this plan will charge your credit card account "
"with the fee of %(vm_price)sCHF/month"
"with %(vm_price)s CHF/month"
msgstr ""
"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(vm_price)sCHF "
"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(vm_price)s CHF "
"pro Monat belastet"
msgid "Place order"
@ -421,6 +430,12 @@ msgstr "Konfiguration"
msgid "including VAT"
msgstr "inkl. Mehrwertsteuer"
msgid "excluding VAT"
msgstr "exkl. Mehrwertsteuer"
msgid "Will be applied at checkout"
msgstr "wird an der Kasse angewendet"
msgid "Billing Address"
msgstr "Rechnungsadresse"
@ -699,6 +714,10 @@ msgstr "Ungültige RAM-Grösse"
msgid "Invalid storage size"
msgstr "Ungültige Speicher-Grösse"
#, python-brace-format
msgid "Incorrect pricing name. Please contact support{support_email}"
msgstr ""
msgid ""
"We could not find the requested VM. Please "
"contact Data Center Light Support."

View file

@ -361,4 +361,13 @@
.locale_date.done{
opacity: 1;
}
.mb-0 {
margin-bottom: 0;
}
.thin-hr {
margin-top: 10px;
margin-bottom: 10px;
}

View file

@ -449,230 +449,6 @@ a.unlink:hover {
color: inherit;
}
/***** DCL payment page **********/
.dcl-order-container {
font-weight: 300;
}
.dcl-order-table-header {
border-bottom: 1px solid #eee;
padding-top: 15px;
padding-bottom: 15px;
font-size: 16px;
color: #333;
text-align: center;
font-weight: 300;
}
.dcl-order-table-content {
border-bottom: 1px solid #eee;
padding-top: 15px;
padding-bottom: 15px;
font-size: 18px;
font-weight: 600;
text-align: center;
}
.tbl-content {
}
.dcl-order-table-total {
border-bottom: 4px solid #eee;
padding-top: 15px;
padding-bottom: 20px;
font-size: 20px;
font-weight: 600;
color: #999;
}
.dcl-order-table-total span {
font-size: 13px;
color: #999;
font-weight: 400;
padding-left: 5px;
}
.dcl-place-order-text{
color: #808080;
}
.dcl-order-table-total .tbl-total {
text-align: center;
color: #000;
padding-left: 44px;
}
.tbl-total .dcl-price-month {
font-size: 16px;
text-transform: capitalize;
color: #000;
}
.tbl-no-padding {
padding: 0px;
}
.dcl-billing-sec {
margin-top: 50px;
}
.dcl-order-sec {
padding: 0 30px;
}
.card-warning-content {
font-weight: 300;
border: 1px solid #a1a1a1;
border-radius: 3px;
padding: 5px;
margin-bottom: 15px;
}
.card-warning-error {
border: 1px solid #EB4D5C;
color: #EB4D5C;
}
.card-warning-addtional-margin {
margin-top: 15px;
}
.stripe-payment-btn {
outline: none;
width: auto;
float: right;
font-style: normal;
font-weight: 300;
position: absolute;
padding-left: 30px;
padding-right: 30px;
right: 0;
}
.card-cvc-element label {
padding-left: 10px;
}
.card-element {
margin-bottom: 10px;
}
.card-element label{
width:100%;
margin-bottom:0px;
}
.my-input {
border-bottom: 1px solid #ccc;
}
.card-cvc-element .my-input {
padding-left: 10px;
}
#card-errors {
clear: both;
padding: 0 0 10px;
color: #eb4d5c;
}
.credit-card-goup{
padding: 0;
}
@media (max-width: 767px) {
.dcl-order-table-total span {
padding-left: 3px;
}
.dcl-order-sec {
padding: 10px 20px 30px 20px;
border-bottom: 4px solid #eee;
}
.tbl-header {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.tbl-content {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.dcl-order-table-header {
border-bottom: 0px solid #eee;
padding: 10px 0;
text-align: left;
}
.dcl-order-table-content {
border-bottom: 0px solid #eee;
padding: 10px 0;
text-align: right;
font-size: 16px;
}
.dcl-order-table-total {
font-size: 18px;
color: #000;
padding: 10px 0;
border-bottom: 0px solid #eee;
}
.dcl-order-table-total .tbl-total {
padding: 0px;
text-align: right;
}
.dcl-billing-sec {
margin-top: 30px;
margin-bottom: 30px;
}
.card-expiry-element {
padding-right: 10px;
}
.card-cvc-element {
padding-left: 10px;
}
#billing-form .form-control {
box-shadow: none !important;
font-weight: 400;
}
}
@media (min-width: 1200px) {
.dcl-order-container {
width: 990px;
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
}
@media (min-width: 768px) {
.dcl-billing {
padding-right: 65px;
border-right: 1px solid #eee;
}
.dcl-creditcard {
padding-left: 65px;
}
.tbl-tot {
padding-left: 17px;
}
.content-dashboard {
/*width: auto !important;*/
}
}
@media only screen and (max-width: 1040px) and (min-width: 768px) {
.content-dashboard {
width: 96% !important;

View file

@ -3,6 +3,7 @@
margin: 100px auto 40px;
border: 1px solid #ccc;
padding: 15px;
color: #595959;
}
@media(min-width: 768px) {
@ -48,10 +49,6 @@
margin-bottom: 15px;
}
.order-detail-container .order-details strong {
color: #595959;
}
.order-detail-container h4 {
font-size: 16px;
font-weight: bold;
@ -60,13 +57,28 @@
.order-detail-container p {
margin-bottom: 5px;
color: #595959;
}
.order-detail-container hr {
margin: 15px 0;
}
.order-detail-container .thin-hr {
margin: 10px 0;
}
.order-detail-container .subtotal-price {
font-size: 16px;
}
.order-detail-container .subtotal-price .text-primary {
font-size: 17px;
}
.order-detail-container .total-price {
font-size: 18px;
}
@media (max-width: 767px) {
.order-confirm-btn {
text-align: center;
@ -96,4 +108,8 @@
#virtual_machine_create_form {
padding: 15px 0;
}
.dcl-place-order-text {
color: #808080;
}

View file

@ -1,19 +1,35 @@
.payment-container {padding-top:70px; padding-bottom: 11%;}
.creditcard-box .panel-title {display: inline;font-weight: bold; font-size:17px;}
.creditcard-box .checkbox.pull-right { margin: 0; }
.creditcard-box .pl-ziro { padding-left: 0px; }
.creditcard-box .form-control.error {
border-color: red;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(255,0,0,0.6);
.payment-container {
padding-top: 70px;
padding-bottom: 11%;
}
.creditcard-box .panel-title {
display: inline;
font-weight: bold;
font-size: 17px;
}
.creditcard-box .checkbox.pull-right {
margin: 0;
}
.creditcard-box .pl-ziro {
padding-left: 0px;
}
.creditcard-box .form-control.error {
border-color: red;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(255, 0, 0, 0.6);
}
.creditcard-box label.error {
font-weight: bold;
color: red;
padding: 2px 8px;
margin-top: 2px;
}
.creditcard-box .payment-errors {
font-weight: bold;
color: red;
@ -21,96 +37,221 @@
margin-top: 2px;
}
/* landing page payment new style */
.last-p {
margin-bottom: 0;
}
.dcl-payment-section {
max-width: 391px;
margin: 0 auto 30px;
padding: 0 10px 30px;
border-bottom: 1px solid #edebeb;
height: 100%;
}
.dcl-payment-section hr{
margin-top: 15px;
margin-bottom: 15px;
}
.dcl-payment-section .top-hr {
margin-left: -10px;
}
.dcl-payment-section h3 {
font-weight: 600;
}
.dcl-payment-section p {
/*padding: 0 5px;*/
font-weight: 400;
}
.dcl-payment-section .card-warning-content {
padding: 8px 10px;
font-weight: 300;
}
.dcl-payment-order strong{
font-size: 17px;
}
.dcl-payment-order p {
font-weight: 300;
}
.dcl-payment-section .form-group {
margin-bottom: 10px;
}
.dcl-payment-section .form-control {
box-shadow: none;
padding: 6px 12px;
height: 32px;
}
.dcl-payment-user {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
.dcl-order-sec {
padding: 0 30px;
}
.dcl-payment-user h4 {
font-weight: 600;
font-size: 17px;
.dcl-billing-sec {
margin-top: 50px;
}
.dcl-order-container {
font-weight: 300;
}
.dcl-order-table-header {
border-bottom: 1px solid #eee;
padding: 15px 10px;
font-size: 16px;
color: #333;
font-weight: 300;
}
.dcl-order-table-content {
border-bottom: 1px solid #eee;
padding: 15px 10px;
font-size: 18px;
font-weight: 600;
}
.dcl-order-table-total {
border-bottom: 4px solid #eee;
padding-top: 15px;
padding-bottom: 20px;
font-size: 20px;
font-weight: 600;
}
.dcl-order-table-total span {
font-size: 13px;
color: #999;
font-weight: 400;
}
.dcl-order-table-total .tbl-total {
text-align: right;
color: #000;
}
.tbl-no-padding {
padding: 0px;
}
.card-warning-content {
font-weight: 300;
border: 1px solid #a1a1a1;
border-radius: 3px;
padding: 5px;
margin-bottom: 15px;
}
.card-warning-error {
border: 1px solid #EB4D5C;
color: #EB4D5C;
}
.card-warning-addtional-margin {
margin-top: 15px;
}
.stripe-payment-btn {
outline: none;
width: auto;
float: right;
font-style: normal;
font-weight: 300;
position: absolute;
padding-left: 30px;
padding-right: 30px;
right: 0;
}
.card-cvc-element label {
padding-left: 10px;
}
.card-element {
margin-bottom: 10px;
}
.card-element label {
width: 100%;
margin-bottom: 0px;
}
.my-input {
border-bottom: 1px solid #ccc;
}
.card-cvc-element .my-input {
padding-left: 10px;
}
#card-errors {
clear: both;
padding: 0 0 10px;
color: #eb4d5c;
}
.credit-card-goup {
padding: 0;
}
@media (max-width: 767px) {
.dcl-order-sec {
padding: 10px 5px 30px;
border-bottom: 4px solid #eee;
}
.dcl-billing-sec {
margin-top: 30px;
margin-bottom: 30px;
padding: 5px;
}
.dcl-billing {
margin-top: 20px;
margin-bottom: 40px;
}
.tbl-header {
border-bottom: 1px solid #eee;
padding-top: 10px;
padding-bottom: 10px;
margin-right: -15px;
}
.dcl-order-table-total .tbl-total {
margin-left: -15px;
}
.dcl-order-table-total .tbl-tot {
margin-right: -15px;
}
.tbl-content {
border-bottom: 1px solid #eee;
padding-top: 10px;
padding-bottom: 10px;
margin-left: -15px;
}
.dcl-order-table-header {
border-bottom: 0px solid #eee;
padding: 10px 0;
text-align: left;
}
.dcl-order-table-content {
border-bottom: 0px solid #eee;
padding: 10px 0;
text-align: right;
font-size: 16px;
}
.dcl-order-table-total {
font-size: 18px;
color: #000;
padding: 10px 0;
border-bottom: 0px solid #eee;
}
.card-expiry-element {
padding-right: 10px;
}
.card-cvc-element {
padding-left: 10px;
}
#billing-form .form-control {
box-shadow: none !important;
font-weight: 400;
}
}
@media (min-width: 768px) {
.dcl-payment-grid {
display: flex;
align-items: stretch;
flex-wrap: wrap;
}
.dcl-payment-box {
width: 50%;
position: relative;
padding: 0 30px;
}
.dcl-payment-box:nth-child(2) {
order: 1;
}
.dcl-payment-box:nth-child(4) {
order: 2;
}
.dcl-payment-section {
padding: 15px 10px;
margin-bottom: 0;
border-bottom-width: 5px;
}
.dcl-payment-box:nth-child(2n) .dcl-payment-section {
border-bottom: none;
}
.dcl-payment-box:nth-child(1):after,
.dcl-payment-box:nth-child(2):after {
content: ' ';
display: block;
background: #eee;
width: 1px;
position: absolute;
right: 0;
z-index: 2;
top: 20px;
bottom: 20px;
}
.dcl-billing {
padding-right: 65px;
border-right: 1px solid #eee;
}
.dcl-creditcard {
padding-left: 65px;
}
.dcl-order-table-total .tbl-total,
.dcl-order-table-total .tbl-tot {
padding: 0 10px;
}
.tbl-header-center,
.tbl-content-center {
text-align: center;
}
.tbl-header-right,
.tbl-content-right {
text-align: right;
}
}
@media (min-width: 1200px) {
.dcl-order-container {
width: 990px;
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
}

View file

@ -1,7 +1,9 @@
/* Create VM calculator */
.price-calc-section {
padding: 80px 40px !important;
padding: 20px 0 !important;
font-weight: 300;
font-size: 18px;
}
@media (max-width: 768px) {
@ -40,19 +42,19 @@
}
.price-calc-section .card {
width: 50%;
border-radius: 7px;
margin: 0 auto;
background: #fff;
box-shadow: 1px 3px 6px 2px rgba(0, 0, 0, 0.2);
padding-bottom: 30px;
text-align: center;
max-width: 320px;
max-width: 4000px;
position: relative;
}
@media (min-width: 768px) {
.price-calc-section .card {
margin-left: 0;
/* margin-left: 0; */
}
}
@ -85,7 +87,7 @@
}
.price-calc-section .card .description {
padding: 7px 8px 2px;
padding: 12px;
position: relative;
display: flex;
justify-content: space-around !important;
@ -93,7 +95,7 @@
}
.price-calc-section .card .description span {
font-size: 14px;
font-size: 16px;
margin-left: 5px;
/* margin-left: 0px; */
/* justify-self: start; */
@ -104,17 +106,18 @@
}
.price-calc-section .card .description .select-number{
font-size: 16px;
font-size: 18px;
text-align: center;
width: 85px;
padding: 5px 10px;
}
.price-calc-section .card .description i {
color: #29427a;
cursor: pointer;
font-size: 20px;
border: 1px solid #ccc;
padding: 5px 6px 3px;
/* border: 1px solid #ccc; */
/* padding: 5px 6px 3px; */
border-radius: 5px;
}
@ -193,7 +196,7 @@
.price-calc-section .help-block.with-errors {
text-align: center;
margin: 0 0;
padding: 0 0 5px;
padding: 0 0;
}
.price-calc-section .help-block.with-errors ul {
margin-bottom: 0;
@ -209,10 +212,10 @@
display: block;
position: absolute;
bottom: 0;
left: 18%;
left: 0;
z-index: 20;
height: 1px;
width: 65%;
width: 100%;
background: rgba(128, 128, 128, 0.2);
}

View file

@ -153,4 +153,87 @@ $( document ).ready(function() {
$('.navbar-fixed-top.topnav').css('padding-right', topnavPadding-scrollbarWidth);
}
});
/* ---------------------------------------------
Scripts initialization
--------------------------------------------- */
var cardPricing = {
'cpu': {
'id': 'coreValue',
'value': 1,
'min': 1,
'max': 48,
'interval': 1
},
'ram': {
'id': 'ramValue',
'value': 2,
'min': 1,
'max': 200,
'interval': 1
},
'storage': {
'id': 'storageValue',
'value': 10,
'min': 10,
'max': 2000,
'interval': 10
}
};
function _initPricing() {
_fetchPricing();
$('.fa-minus-circle.left').click(function(event) {
var data = $(this).data('minus');
if (cardPricing[data].value > cardPricing[data].min) {
cardPricing[data].value = Number(cardPricing[data].value) - cardPricing[data].interval;
}
_fetchPricing();
});
$('.fa-plus-circle.right').click(function(event) {
var data = $(this).data('plus');
if (cardPricing[data].value < cardPricing[data].max) {
cardPricing[data].value = Number(cardPricing[data].value) + cardPricing[data].interval;
}
_fetchPricing();
});
$('.input-price').change(function() {
var data = $(this).attr("name");
cardPricing[data].value = $('input[name=' + data + ']').val();
_fetchPricing();
});
}
function _fetchPricing() {
Object.keys(cardPricing).map(function(element) {
$('input[name=' + element + ']').val(cardPricing[element].value);
});
_calcPricing();
}
function _calcPricing() {
if(typeof window.coresUnitPrice === 'undefined'){
window.coresUnitPrice = 5;
}
if(typeof window.ramUnitPrice === 'undefined'){
window.ramUnitPrice = 2;
}
if(typeof window.ssdUnitPrice === 'undefined'){
window.ssdUnitPrice = 0.6;
}
if(typeof window.discountAmount === 'undefined'){
window.discountAmount = 0;
}
var total = (cardPricing['cpu'].value * window.coresUnitPrice) +
(cardPricing['ram'].value * window.ramUnitPrice) +
(cardPricing['storage'].value * window.ssdUnitPrice) -
window.discountAmount;
total = parseFloat(total.toFixed(2));
$("#total").text(total);
}
_initPricing();
});

View file

@ -1,5 +1,5 @@
{% load staticfiles bootstrap3%}
{% load i18n %}
{% load staticfiles i18n cms_tags sekizai_tags %}
<!DOCTYPE html>
<html lang="en">
@ -29,6 +29,9 @@
{% block css_extra %}
{% endblock css_extra %}
{% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %}
{% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %}
<!-- Custom Fonts -->
<link href='//fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
<link href="{% static 'datacenterlight/font-awesome/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
@ -48,7 +51,7 @@
</head>
<body>
{% cms_toolbar %}
{% block navbar %}
{% include "hosting/includes/_navbar_user.html" %}

View file

@ -1,7 +1,9 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 i18n %}
{% load staticfiles bootstrap3 i18n cms_tags %}
{% block content %}
<div class="dashboard-container create-vm-container">
<div class="row">
<div class="col-sm-5">
@ -17,14 +19,8 @@
{% endif %}
</div>
</div>
<div class="col-sm-6">
<div class="price-calc-section no-padding">
<div class="landing card">
<div class="caption">
{% include "hosting/calculator_form.html" %}
</div>
</div>
</div>
<div class="col-sm-6 hosting-calculator">
{% render_placeholder cms_integration.calculator_placeholder %}
</div>
</div>
</div>

View file

@ -114,37 +114,58 @@
<p>
<span>{% trans "Cores" %}: </span>
{% if vm.cores %}
<span class="pull-right">{{vm.cores|floatformat}}</span>
<strong class="pull-right">{{vm.cores|floatformat}}</strong>
{% else %}
<span class="pull-right">{{vm.cpu|floatformat}}</span>
<strong class="pull-right">{{vm.cpu|floatformat}}</strong>
{% endif %}
</p>
<p>
<span>{% trans "Memory" %}: </span>
<span class="pull-right">{{vm.memory}} GB</span>
<strong class="pull-right">{{vm.memory}} GB</strong>
</p>
<p>
<span>{% trans "Disk space" %}: </span>
<span class="pull-right">{{vm.disk_size}} GB</span>
<strong class="pull-right">{{vm.disk_size}} GB</strong>
</p>
{% if vm.vat > 0 %}
<p>
<strong>{% trans "Subtotal" %}: </strong>
<span class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</span>
</p>
<p>
<span>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%): </span>
<span class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</span>
</p>
{% endif %}
<p>
<strong>{% trans "Total" %}</strong>
<span class="pull-right">{% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} CHF</span>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
{% if vm.vat > 0 or vm.discount.amount > 0 %}
<div class="col-sm-6">
<div class="subtotal-price">
{% if vm.vat > 0 %}
<p>
<strong>{% trans "Subtotal" %} </strong>
<strong class="pull-right">{{vm.price|floatformat:2|intcomma}} CHF</strong>
</p>
<p>
<small>{% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) </small>
<strong class="pull-right">{{vm.vat|floatformat:2|intcomma}} CHF</strong>
</p>
{% endif %}
{% if vm.discount.amount > 0 %}
<p class="text-primary">
{%trans "Discount" as discount_name %}
<strong>{{ vm.discount.name|default:discount_name }} </strong>
<strong class="pull-right">- {{ vm.discount.amount }} CHF</strong>
</p>
{% endif %}
</div>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
{% endif %}
<div class="col-sm-6">
<p class="total-price">
<strong>{% trans "Total" %} </strong>
<strong class="pull-right">{% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} CHF</strong>
</p>
</div>
</div>
</div>
<hr>
<hr class="thin-hr">
</div>
{% if not order %}
{% block submit_btn %}
@ -152,7 +173,7 @@
{% csrf_token %}
<div class="row">
<div class="col-sm-8">
<div class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price|intcomma }}CHF/month{% endblocktrans %}.</div>
<div class="dcl-place-order-text">{% blocktrans with vm_price=vm.total_price|floatformat:2|intcomma %}By clicking "Place order" this plan will charge your credit card account with {{ vm_price }} CHF/month{% endblocktrans %}.</div>
</div>
<div class="col-sm-4 order-confirm-btn text-right">
<button class="btn choice-btn" id="btn-create-vm" data-href="{% url 'hosting:order-confirmation' %}" data-toggle="modal" data-target="#createvm-modal">

View file

@ -9,159 +9,208 @@
<!-- Credit card form -->
<div class="dcl-order-container">
<div class="payment-container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 dcl-order-sec">
<h3><strong>{%trans "Your Order" %}</strong></h3>
<div class="col-xs-6 col-sm-12 col-md-12 col-lg-12 dcl-order-table-header">
<div class="col-xs-12 col-sm-2 col-md-1 col-lg-1 tbl-header">
{%trans "Cores" %}
</div>
<div class="col-xs-12 col-sm-3 col-md-4 col-lg-4 tbl-header">
{%trans "Memory" %}
</div>
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3 tbl-header">
{%trans "Disk space" %}
</div>
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 tbl-header">
{%trans "Configuration" %}
<div class="dcl-order-sec">
<h3><strong>{%trans "Your Order" %}</strong></h3>
<div class="row">
<div class="col-xs-6 col-sm-12">
<div class="dcl-order-table-header">
<div class="row">
<div class="col-sm-2">
<div class="tbl-header">
{%trans "Cores" %}
</div>
</div>
<div class="col-sm-4">
<div class="tbl-header tbl-header-center">
{%trans "Memory" %}
</div>
</div>
<div class="col-sm-3">
<div class="tbl-header tbl-header-center">
{%trans "Disk space" %}
</div>
</div>
<div class="col-sm-3">
<div class="tbl-header tbl-header-right">
{%trans "Configuration" %}
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-12 col-md-12 col-lg-12 dcl-order-table-content">
<div class="col-xs-12 col-sm-2 col-md-1 col-lg-1 tbl-content">
{{request.session.specs.cpu|floatformat}}
</div>
<div class="col-xs-12 col-sm-3 col-md-4 col-lg-4 tbl-content">
{{request.session.specs.memory|floatformat}} GB
</div>
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3 tbl-content">
{{request.session.specs.disk_size|floatformat|intcomma}} GB
</div>
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 tbl-content">
{{request.session.template.name}}
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 dcl-order-table-total">
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 tbl-tot tbl-no-padding">
{%trans "Total" %} <span>{%trans "including VAT" %}</span>
</div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 tbl-no-padding">
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4"></div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 tbl-total">{{request.session.specs.price|intcomma}}
CHF<span class="dcl-price-month">/{% trans "Month" %}</span>
<div class="col-xs-6 col-sm-12">
<div class="dcl-order-table-content">
<div class="row">
<div class="col-sm-2">
<div class="tbl-content">
{{request.session.specs.cpu|floatformat}}
</div>
</div>
<div class="col-sm-4">
<div class="tbl-content tbl-content-center">
{{request.session.specs.memory|floatformat}} GB
</div>
</div>
<div class="col-sm-3">
<div class="tbl-content tbl-content-center">
{{request.session.specs.disk_size|floatformat|intcomma}} GB
</div>
</div>
<div class="col-sm-3">
<div class="tbl-content tbl-content-right">
{{request.session.template.name}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 dcl-billing-sec">
<div class="col-xs-12 col-sm-5 col-md-6 billing dcl-billing">
<h3><b>{%trans "Billing Address"%}</b></h3>
<hr>
<form role="form" id="billing-form" method="post" action="" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
</form>
<div class="dcl-order-table-total">
<div class="row">
<div class="col-xs-6">
<div class="tbl-tot">
{%trans "Total" %}&nbsp;
<span>{% if vm_pricing.vat_inclusive %}{%trans "including VAT" %}{% else %}{%trans "excluding VAT" %}{% endif %}</span>
</div>
</div>
<div class="col-xs-6">
<div class="tbl-total">
{{request.session.specs.price|intcomma}} CHF/{% trans "Month" %}
</div>
</div>
</div>
<div class="col-xs-12 col-sm-7 col-md-6 creditcard-box dcl-creditcard">
<h3><b>{%trans "Credit Card"%}</b></h3>
<hr>
<div>
<p>
{% blocktrans %}Please fill in your credit card information below. We are using <a href="https://stripe.com" target="_blank">Stripe</a> for payment and do not store your information in our database.{% endblocktrans %}
</p>
{% if vm_pricing.discount_amount %}
<hr class="thin-hr">
<div class="row">
<div class="col-xs-6">
<div class="tbl-tot">
{%trans "Discount" as discount_name %}
{{ vm_pricing.discount_name|default:discount_name }}&nbsp;&nbsp;<br>
<span>({% trans "Will be applied at checkout" %})</span>
</div>
</div>
<div class="col-xs-6 text-right">
<div class="tbl-total">
<div class="text-primary">- {{ vm_pricing.discount_amount }} CHF/{% trans "Month" %}</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
<div class="dcl-billing-sec">
<div class="row">
<div class="col-sm-5 col-md-6">
<div class="billing dcl-billing">
<h3><b>{%trans "Billing Address"%}</b></h3>
<hr>
<form role="form" id="billing-form" method="post" action="" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
</form>
</div>
</div>
<div class="col-sm-7 col-md-6">
<div class="creditcard-box dcl-creditcard">
<h3><b>{%trans "Credit Card"%}</b></h3>
<hr>
<div>
{% if credit_card_data.last4 %}
<form role="form" id="payment-form-with-creditcard" novalidate>
<h5 class="billing-head">Credit Card</h5>
<h5 class="membership-lead">Last 4: *****{{credit_card_data.last4}}</h5>
<h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5>
<input type="hidden" name="credit_card_needed" value="false"/>
</form>
{% if not messages and not form.non_field_errors %}
<p class="card-warning-content card-warning-addtional-margin">
{% trans "You are not making any payment yet. After submitting your card information, you will be taken to the Confirm Order Page." %}
</p>
{% endif %}
<div id='payment_error'>
{% for message in messages %}
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
<ul class="list-unstyled">
<li>
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
</li>
</ul>
{% endif %}
{% endfor %}
{% for error in form.non_field_errors %}
<p class="card-warning-content card-warning-error">
{{ error|escape }}
<p>
{% blocktrans %}Please fill in your credit card information below. We are using <a href="https://stripe.com" target="_blank">Stripe</a> for payment and do not store your information in our database.{% endblocktrans %}
</p>
<div>
{% if credit_card_data.last4 %}
<form role="form" id="payment-form-with-creditcard" novalidate>
<h5 class="billing-head">Credit Card</h5>
<h5 class="membership-lead">Last 4: *****{{credit_card_data.last4}}</h5>
<h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5>
<input type="hidden" name="credit_card_needed" value="false"/>
</form>
{% if not messages and not form.non_field_errors %}
<p class="card-warning-content card-warning-addtional-margin">
{% trans "You are not making any payment yet. After submitting your card information, you will be taken to the Confirm Order Page." %}
</p>
{% endfor %}
</div>
<div class="text-right">
<button id="payment_button_with_creditcard" class="btn btn-vm-contact" type="submit">{%trans "SUBMIT" %}</button>
</div>
{% else %}
<form action="" id="payment-form-new" method="POST">
<input type="hidden" name="token"/>
<div class="group">
<div class="credit-card-goup">
<div class="card-element card-number-element">
<label>{%trans "Card Number" %}</label>
<div id="card-number-element" class="field my-input"></div>
</div>
<div class="row">
<div class="col-xs-5 card-element card-expiry-element">
<label>{%trans "Expiry Date" %}</label>
<div id="card-expiry-element" class="field my-input"></div>
</div>
<div class="col-xs-3 col-xs-offset-4 card-element card-cvc-element">
<label>{%trans "CVC" %}</label>
<div id="card-cvc-element" class="field my-input"></div>
</div>
</div>
<div class="card-element brand">
<label>{%trans "Card Type" %}</label>
<i class="pf pf-credit-card" id="brand-icon"></i>
</div>
</div>
</div>
<div id="card-errors"></div>
{% if not messages and not form.non_field_errors %}
<p class="card-warning-content">
{% trans "You are not making any payment yet. After submitting your card information, you will be taken to the Confirm Order Page." %}
{% endif %}
<div id='payment_error'>
{% for message in messages %}
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
<ul class="list-unstyled">
<li>
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
</li>
</ul>
{% endif %}
{% endfor %}
{% for error in form.non_field_errors %}
<p class="card-warning-content card-warning-error">
{{ error|escape }}
</p>
{% endif %}
<div id='payment_error'>
{% for message in messages %}
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
<ul class="list-unstyled">
<li>
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
</li>
</ul>
{% endif %}
{% endfor %}
{% for error in form.non_field_errors %}
<p class="card-warning-content card-warning-error">
{{ error|escape }}
{% endfor %}
</div>
<div class="text-right">
<button id="payment_button_with_creditcard" class="btn btn-vm-contact" type="submit">{%trans "SUBMIT" %}</button>
</div>
{% else %}
<form action="" id="payment-form-new" method="POST">
<input type="hidden" name="token"/>
<div class="group">
<div class="credit-card-goup">
<div class="card-element card-number-element">
<label>{%trans "Card Number" %}</label>
<div id="card-number-element" class="field my-input"></div>
</div>
<div class="row">
<div class="col-xs-5 card-element card-expiry-element">
<label>{%trans "Expiry Date" %}</label>
<div id="card-expiry-element" class="field my-input"></div>
</div>
<div class="col-xs-3 col-xs-offset-4 card-element card-cvc-element">
<label>{%trans "CVC" %}</label>
<div id="card-cvc-element" class="field my-input"></div>
</div>
</div>
<div class="card-element brand">
<label>{%trans "Card Type" %}</label>
<i class="pf pf-credit-card" id="brand-icon"></i>
</div>
</div>
</div>
<div id="card-errors"></div>
{% if not messages and not form.non_field_errors %}
<p class="card-warning-content">
{% trans "You are not making any payment yet. After submitting your card information, you will be taken to the Confirm Order Page." %}
</p>
{% endfor %}
</div>
<div class="text-right">
<button class="btn btn-vm-contact btn-wide" type="submit">{%trans "SUBMIT" %}</button>
</div>
</div>
{% endif %}
<div id='payment_error'>
{% for message in messages %}
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
<ul class="list-unstyled">
<li>
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
</li>
</ul>
{% endif %}
{% endfor %}
<div style="display:none;">
<p class="payment-errors"></p>
</div>
</form>
{% endif %}
{% for error in form.non_field_errors %}
<p class="card-warning-content card-warning-error">
{{ error|escape }}
</p>
{% endfor %}
</div>
<div class="text-right">
<button class="btn btn-vm-contact btn-wide" type="submit">{%trans "SUBMIT" %}</button>
</div>
</div>
<div style="display:none;">
<p class="payment-errors"></p>
</div>
</form>
{% endif %}
</div>
</div>
</div>
</div>

View file

@ -31,8 +31,8 @@ from stored_messages.api import mark_read
from stored_messages.models import Message
from stored_messages.settings import stored_messages_settings
from datacenterlight.models import VMTemplate
from datacenterlight.utils import create_vm
from datacenterlight.models import VMTemplate, VMPricing
from datacenterlight.utils import create_vm, get_cms_integration
from membership.models import CustomUser, StripeCustomer
from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import (
@ -43,7 +43,7 @@ from utils.forms import (
BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm,
ResendActivationEmailForm
)
from utils.hosting_utils import get_vm_price, get_vm_price_with_vat
from utils.hosting_utils import get_vm_price_with_vat
from utils.mailer import BaseEmail
from utils.stripe_utils import StripeUtils
from utils.tasks import send_plain_email_task
@ -652,7 +652,10 @@ class PaymentVMView(LoginRequiredMixin, FormView):
})
context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
'stripe_key': settings.STRIPE_API_PUBLIC_KEY,
'vm_pricing': VMPricing.get_vm_pricing_by_name(
self.request.session.get('specs', {}).get('pricing_name')
),
})
return context
@ -750,7 +753,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
context['vm'] = vm_detail.__dict__
context['vm']['name'] = '{}-{}'.format(
context['vm']['configuration'], context['vm']['vm_id'])
price, vat, vat_percent = get_vm_price_with_vat(
price, vat, vat_percent, discount = get_vm_price_with_vat(
cpu=context['vm']['cores'],
ssd_size=context['vm']['disk_size'],
memory=context['vm']['memory'],
@ -759,8 +762,9 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
)
context['vm']['vat'] = vat
context['vm']['price'] = price
context['vm']['discount'] = discount
context['vm']['vat_percent'] = vat_percent
context['vm']['total_price'] = price + vat
context['vm']['total_price'] = price + vat - discount['amount']
context['subscription_end_date'] = vm_detail.end_date()
except VMDetail.DoesNotExist:
try:
@ -769,7 +773,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
)
vm = manager.get_vm(obj.vm_id)
context['vm'] = VirtualMachineSerializer(vm).data
price, vat, vat_percent = get_vm_price_with_vat(
price, vat, vat_percent, discount = get_vm_price_with_vat(
cpu=context['vm']['cores'],
ssd_size=context['vm']['disk_size'],
memory=context['vm']['memory'],
@ -778,8 +782,10 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
)
context['vm']['vat'] = vat
context['vm']['price'] = price
context['vm']['discount'] = discount
context['vm']['vat_percent'] = vat_percent
context['vm']['total_price'] = price + vat
context['vm']['total_price'] = price + \
vat - discount['amount']
except WrongIdError:
messages.error(
self.request,
@ -855,7 +861,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
cpu = specs.get('cpu')
memory = specs.get('memory')
disk_size = specs.get('disk_size')
amount_to_be_charged = specs.get('price')
amount_to_be_charged = specs.get('total_price')
plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
memory=memory,
disk_size=disk_size)
@ -1000,7 +1006,10 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
@method_decorator(decorators)
def get(self, request, *args, **kwargs):
context = {'templates': VMTemplate.objects.all()}
context = {
'templates': VMTemplate.objects.all(),
'cms_integration': get_cms_integration('default'),
}
return render(request, self.template_name, context)
@method_decorator(decorators)
@ -1012,18 +1021,34 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
storage = request.POST.get('storage')
storage_field = forms.IntegerField(validators=[self.validate_storage])
template_id = int(request.POST.get('config'))
pricing_name = request.POST.get('pricing_name')
vm_pricing = VMPricing.get_vm_pricing_by_name(pricing_name)
template = VMTemplate.objects.filter(
opennebula_vm_template_id=template_id).first()
template_data = VMTemplateSerializer(template).data
if vm_pricing is None:
vm_pricing_name_msg = _(
"Incorrect pricing name. Please contact support"
"{support_email}".format(
support_email=settings.DCL_SUPPORT_FROM_ADDRESS
)
)
messages.add_message(
self.request, messages.ERROR, vm_pricing_name_msg,
extra_tags='pricing'
)
return redirect(CreateVirtualMachinesView.as_view())
else:
vm_pricing_name = vm_pricing.name
try:
cores = cores_field.clean(cores)
except ValidationError as err:
msg = '{} : {}.'.format(cores, str(err))
messages.add_message(self.request, messages.ERROR, msg,
extra_tags='cores')
return HttpResponseRedirect(
reverse('datacenterlight:index') + "#order_form")
return redirect(CreateVirtualMachinesView.as_view())
try:
memory = memory_field.clean(memory)
@ -1031,8 +1056,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
msg = '{} : {}.'.format(memory, str(err))
messages.add_message(self.request, messages.ERROR, msg,
extra_tags='memory')
return HttpResponseRedirect(
reverse('datacenterlight:index') + "#order_form")
return redirect(CreateVirtualMachinesView.as_view())
try:
storage = storage_field.clean(storage)
@ -1040,15 +1064,25 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
msg = '{} : {}.'.format(storage, str(err))
messages.add_message(self.request, messages.ERROR, msg,
extra_tags='storage')
return HttpResponseRedirect(
reverse('datacenterlight:index') + "#order_form")
price = get_vm_price(cpu=cores, memory=memory,
disk_size=storage)
return redirect(CreateVirtualMachinesView.as_view())
price, vat, vat_percent, discount = get_vm_price_with_vat(
cpu=cores,
memory=memory,
ssd_size=storage,
pricing_name=vm_pricing_name
)
specs = {
'cpu': cores,
'memory': memory,
'disk_size': storage,
'price': price
'discount': discount,
'price': price,
'vat': vat,
'vat_percent': vat_percent,
'total_price': price + vat - discount['amount'],
'pricing_name': vm_pricing_name
}
request.session['specs'] = specs
@ -1232,7 +1266,10 @@ class VirtualMachineView(LoginRequiredMixin, View):
["%s=%s" % (k, v) for (k, v) in admin_email_body.items()]),
}
send_plain_email_task.delay(email_to_admin_data)
return JsonResponse(response)
return HttpResponse(
json.dumps(response),
content_type="application/json"
)
class HostingBillListView(PermissionRequiredMixin, LoginRequiredMixin,