Merge pull request #397 from pcoder/task/3580/expand_input_field_on_credit_card

This PR rearranges the components in the payment form. 

- We introduced a new field "Cardholder's Name" as part of the billing address. 
- The stripe input fields are mounted individually.
- The overlapping of date field in the mobile view of the confirm order page is fixed.
- We now have customized place holder texts and customized styles for the stripe input fields.

Task/3580/expand input field on credit card
This commit is contained in:
Pcoder 2017-07-17 20:12:22 +02:00 committed by GitHub
commit 4fa6e7ae4c
10 changed files with 1030 additions and 631 deletions

View file

@ -25,7 +25,13 @@
</div> </div>
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-12 col-sm-6 pull-right text-left">
<address>
<strong>{% trans "Date"%}:</strong><br>
<span id="order-created_at">{% now "Y-m-d H:i" %}</span><br><br>
</address>
</div>
<div class="col-xs-12 col-sm-6">
<address> <address>
<h3><b>{% trans "Billed To:"%}</b></h3> <h3><b>{% trans "Billed To:"%}</b></h3>
{% with request.session.billing_address_data as billing_address %} {% with request.session.billing_address_data as billing_address %}
@ -34,13 +40,6 @@
{% endwith %} {% endwith %}
</address> </address>
</div> </div>
<div class="col-xs-6 text-right">
<address>
<strong>{% trans "Date"%}:</strong><br>
<span id="order-created_at">{% now "Y-m-d H:i" %}</span><br><br>
</address>
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">

File diff suppressed because it is too large Load diff

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-07-11 00:02+0530\n" "POT-Creation-Date: 2017-07-17 00:53+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:68 #: templates/hosting/base_short.html:71
msgid "My Virtual Machines" msgid "My Virtual Machines"
msgstr "Meine virtuellen Maschinen" msgstr "Meine virtuellen Maschinen"
#: templates/hosting/base_short.html:73 templates/hosting/orders.html.py:12 #: templates/hosting/base_short.html:76 templates/hosting/orders.html.py:12
msgid "My Orders" msgid "My Orders"
msgstr "Meine Bestellungen" msgstr "Meine Bestellungen"
#: templates/hosting/base_short.html:82 #: templates/hosting/base_short.html:85
msgid "Keys" msgid "Keys"
msgstr "Schlüssel" msgstr "Schlüssel"
#: templates/hosting/base_short.html:87 #: templates/hosting/base_short.html:90
msgid "Notifications " msgid "Notifications "
msgstr "Benachrichtigungen" msgstr "Benachrichtigungen"
#: templates/hosting/base_short.html:90 #: templates/hosting/base_short.html:93
msgid "Logout" msgid "Logout"
msgstr "Abmelden" msgstr "Abmelden"
#: templates/hosting/base_short.html:95 #: templates/hosting/base_short.html:98
msgid "How it works" msgid "How it works"
msgstr "So funktioniert es" msgstr "So funktioniert es"
#: templates/hosting/base_short.html:98 #: templates/hosting/base_short.html:101
msgid "Your infrastructure" msgid "Your infrastructure"
msgstr "deine Infrastruktur" msgstr "deine Infrastruktur"
#: templates/hosting/base_short.html:101 #: templates/hosting/base_short.html:104
msgid "Our inftrastructure" msgid "Our inftrastructure"
msgstr "Unsere Infrastruktur" msgstr "Unsere Infrastruktur"
#: templates/hosting/base_short.html:104 #: templates/hosting/base_short.html:107
msgid "Pricing" msgid "Pricing"
msgstr "Preise" msgstr "Preise"
#: templates/hosting/base_short.html:107 #: templates/hosting/base_short.html:110
msgid "Contact" msgid "Contact"
msgstr "Kontakt" msgstr "Kontakt"
#: templates/hosting/base_short.html:110 #: templates/hosting/base_short.html:113
#: 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
@ -289,23 +289,23 @@ msgstr "Bezahlmethode"
msgid "Order summary" msgid "Order summary"
msgstr "Bestellungsübersicht" msgstr "Bestellungsübersicht"
#: templates/hosting/order_detail.html:65 templates/hosting/payment.html:17 #: templates/hosting/order_detail.html:65 templates/hosting/payment.html:13
#: templates/hosting/virtual_machine_detail.html:76 #: templates/hosting/virtual_machine_detail.html:76
msgid "Cores" msgid "Cores"
msgstr "Prozessorkerne" msgstr "Prozessorkerne"
#: templates/hosting/order_detail.html:67 templates/hosting/payment.html:20 #: templates/hosting/order_detail.html:67 templates/hosting/payment.html:16
#: templates/hosting/virtual_machine_detail.html:82 #: templates/hosting/virtual_machine_detail.html:82
msgid "Memory" msgid "Memory"
msgstr "Arbeitsspeicher" msgstr "Arbeitsspeicher"
#: templates/hosting/order_detail.html:69 templates/hosting/payment.html:23 #: templates/hosting/order_detail.html:69 templates/hosting/payment.html:19
msgid "Disk space" msgid "Disk space"
msgstr "Festplattenkapazität" msgstr "Festplattenkapazität"
#: templates/hosting/order_detail.html:71 #: templates/hosting/order_detail.html:71 templates/hosting/payment.html:41
msgid "Total" msgid "Total"
msgstr "" msgstr "Gesamt"
#: templates/hosting/order_detail.html:77 #: templates/hosting/order_detail.html:77
msgid "Finish Configuration" msgid "Finish Configuration"
@ -349,46 +349,98 @@ msgstr "Schliessen"
msgid "Delete" msgid "Delete"
msgstr "Löschen" msgstr "Löschen"
#: templates/hosting/payment.html:12 #: templates/hosting/payment.html:10
msgid "Billing Amount" msgid "Your Order"
msgstr "Rechnungsbetrag" msgstr "Deine Bestellung"
#: templates/hosting/payment.html:26 #: templates/hosting/payment.html:22
#: templates/hosting/virtual_machine_detail.html:98 #: templates/hosting/virtual_machine_detail.html:98
msgid "Configuration" msgid "Configuration"
msgstr "Konfiguration" msgstr "Konfiguration"
#: templates/hosting/payment.html:38 #: templates/hosting/payment.html:41
msgid "including VAT"
msgstr "inkl. Mehrwertsteuer"
#: templates/hosting/payment.html:55
msgid "Billing Address" msgid "Billing Address"
msgstr "Rechnungsadresse" msgstr "Rechnungsadresse"
#: templates/hosting/payment.html:52 #: templates/hosting/payment.html:66
msgid "Credit Card" msgid "Credit Card"
msgstr "Kreditkarte" msgstr "Kreditkarte"
#: templates/hosting/payment.html:56 #: templates/hosting/payment.html:71
msgid "" msgid ""
"Please fill in your credit card information below. We are using <a href=" "\n"
"\"https://stripe.com\" target=\"_blank\">Stripe</a> for payment and do not " " Please fill in your credit card information "
"store your information in our database." "below. We are using <a\n"
" href=\"https://stripe.com\" target="
"\"_blank\">Stripe</a> for payment and do not store\n"
" your information in our database.\n"
" "
msgstr "" msgstr ""
"Bitte füll deine Kreditkarteninformationen unten aus. Wir nutzen <a href=" "\n"
"Bitte füll Deine Kreditkarteninformationen unten aus. Wir nutzen <a href="
"\"https://stripe.com\" target=\"_blank\">Stripe</a> für die Bezahlung und " "\"https://stripe.com\" target=\"_blank\">Stripe</a> für die Bezahlung und "
"speichern keine Informationen in unserer Datenbank." "speichern keine Informationen in unserer Datenbank."
#: templates/hosting/payment.html:71 templates/hosting/payment.html.py:96 #: templates/hosting/payment.html:90
msgid "" msgid ""
"You are not making any payment yet. After submitting your card information, " "\n"
"you will be taken to the Confirm Order Page." " You are not making any payment yet. "
"After submitting your card\n"
" information, you will be taken to "
"the Confirm Order Page.\n"
" "
msgstr "" msgstr ""
"Es wird noch keine Bezahlung vorgenommen. Nach der Eingabe deiner " "\n"
"Es wird noch keine Bezahlung vorgenommen. Nach der Eingabe Deiner "
"Kreditkateninformationen wirst du auf die Bestellbestätigungsseite " "Kreditkateninformationen wirst du auf die Bestellbestätigungsseite "
"weitergeleitet." "weitergeleitet."
#: templates/hosting/payment.html:76 templates/hosting/payment.html.py:100 #: templates/hosting/payment.html:101 templates/hosting/payment.html.py:143
msgid "Submit" msgid "Submit"
msgstr "Absenden" msgstr "Absenden"
#: templates/hosting/payment.html:113
msgid "Card Number"
msgstr "Kreditkartennummer"
#: templates/hosting/payment.html:117
msgid "Expiry Date"
msgstr "Ablaufdatum"
#: templates/hosting/payment.html:122
msgid "CVC"
msgstr ""
#: templates/hosting/payment.html:126
msgid "Card Type"
msgstr "Kartentyp"
#: templates/hosting/payment.html:135
msgid ""
"\n"
" You are not making any payment "
"yet. After submitting your card\n"
" information, you will be taken "
"to the Confirm Order Page.\n"
" "
msgstr ""
"\n"
"Es wird noch keine Bezahlung vorgenommen. Nach der Eingabe Deiner "
"Kreditkateninformationen wirst du auf die Bestellbestätigungsseite "
"weitergeleitet."
#: templates/hosting/payment.html:178
msgid "Processing"
msgstr "Weiter"
#: templates/hosting/payment.html:179
msgid "Enter your credit card number"
msgstr "Deine Kreditkartennummer"
#: templates/hosting/reset_password.html:15 #: templates/hosting/reset_password.html:15
msgid "Reset your password" msgid "Reset your password"
msgstr "Passwort zurücksetzen" msgstr "Passwort zurücksetzen"
@ -529,12 +581,15 @@ msgstr "Du kannst dich nun"
msgid "Sorry. Your request is invalid." msgid "Sorry. Your request is invalid."
msgstr "Entschuldigung, deine Anfrage ist ungültig." msgstr "Entschuldigung, deine Anfrage ist ungültig."
#: views.py:756 #: views.py:757
msgid "" msgid ""
"We could not find the requested VM. Please " "We could not find the requested VM. Please "
"contact Data Center Light Support." "contact Data Center Light Support."
msgstr "" msgstr ""
#~ msgid "Billing Amount"
#~ msgstr "Rechnungsbetrag"
#~ msgid "Payment Details" #~ msgid "Payment Details"
#~ msgstr "Rechnungsdetails" #~ msgstr "Rechnungsdetails"
@ -552,15 +607,9 @@ msgstr ""
#~ msgid "CARD NUMBER" #~ msgid "CARD NUMBER"
#~ msgstr "Kreditkartennummer" #~ msgstr "Kreditkartennummer"
#~ msgid "Valid Card Number"
#~ msgstr "Gültige Kreditkartennummer"
#~ msgid "EXPIRATION DATE" #~ msgid "EXPIRATION DATE"
#~ msgstr "Ablaufdatum" #~ msgstr "Ablaufdatum"
#~ msgid "CV CODE"
#~ msgstr "CV Code"
#~ msgid "Home" #~ msgid "Home"
#~ msgstr "Home" #~ msgstr "Home"

View file

@ -4,14 +4,15 @@
* For details, see http://www.apache.org/licenses/LICENSE-2.0. * For details, see http://www.apache.org/licenses/LICENSE-2.0.
*/ */
@font-face { @font-face {
font-family: 'Lato-Regular'; font-family: 'Lato-Regular';
src: url('../fonts/Lato/Lato-Regular.ttf'); src: url('../fonts/Lato/Lato-Regular.ttf');
} }
@font-face { @font-face {
src: url('../fonts/Lato/Lato-Black.ttf'); src: url('../fonts/Lato/Lato-Black.ttf');
} }
@font-face { @font-face {
font-family: 'Lato-Light'; font-family: 'Lato-Light';
src: url('../fonts/Lato/Lato-Light.ttf'); src: url('../fonts/Lato/Lato-Light.ttf');
@ -33,6 +34,7 @@ h6 {
font-family: 'Lato-Regular', sans-serif; font-family: 'Lato-Regular', sans-serif;
font-weight: 300; font-weight: 300;
} }
.topnav { .topnav {
font-size: 14px; font-size: 14px;
} }
@ -191,11 +193,13 @@ h6 {
float: right; float: right;
margin-top: 0; margin-top: 0;
} }
/*------Auth section---------*/ /*------Auth section---------*/
.auth-container { .auth-container {
height: 100vh; height: 100vh;
position: relative; position: relative;
} }
.auth-bg { .auth-bg {
background: url(../img/auth-bg.jpg); background: url(../img/auth-bg.jpg);
position: fixed; position: fixed;
@ -209,6 +213,7 @@ h6 {
background-attachment: fixed; background-attachment: fixed;
} }
.auth-bg::before { .auth-bg::before {
content: ""; content: "";
position: absolute; position: absolute;
@ -219,14 +224,17 @@ h6 {
background: rgba(75, 75, 101, 0.55); background: rgba(75, 75, 101, 0.55);
z-index: 1; z-index: 1;
} }
.auth-container .container { .auth-container .container {
z-index: 1000; z-index: 1000;
} }
.auth-container .auth-content { .auth-container .auth-content {
width: 100%; width: 100%;
margin: 0 auto; margin: 0 auto;
max-width: 390px; max-width: 390px;
} }
.auth-container .auth-center { .auth-container .auth-center {
position: absolute; position: absolute;
left: 50%; left: 50%;
@ -238,6 +246,7 @@ h6 {
.auth-container .auth-title { .auth-container .auth-title {
margin-bottom: 50px; margin-bottom: 50px;
} }
.auth-container .auth-title h2 { .auth-container .auth-title h2 {
color: #fff; color: #fff;
font-size: 44px; font-size: 44px;
@ -247,6 +256,7 @@ h6 {
margin-bottom: 30px; margin-bottom: 30px;
position: relative; position: relative;
} }
.auth-container .auth-title h2::after { .auth-container .auth-title h2::after {
content: ""; content: "";
position: absolute; position: absolute;
@ -279,34 +289,42 @@ h6 {
border-radius: 3px 3px 0px 0px; border-radius: 3px 3px 0px 0px;
margin: 0 auto; margin: 0 auto;
} }
.auth-box .form { .auth-box .form {
padding: 20px; padding: 20px;
width: 80%; width: 80%;
margin: 0 auto; margin: 0 auto;
} }
.auth-box .form .red { .auth-box .form .red {
color: #ea3a3a; color: #ea3a3a;
} }
.auth-box .form .btn { .auth-box .form .btn {
box-shadow: 0 0px 9px rgba(0, 0, 0, 0.19), 0 3px 5px rgba(0, 0, 0, 0.23); box-shadow: 0 0px 9px rgba(0, 0, 0, 0.19), 0 3px 5px rgba(0, 0, 0, 0.23);
letter-spacing: 3px; letter-spacing: 3px;
font-size: 17px; font-size: 17px;
text-transform: uppercase; text-transform: uppercase;
} }
.auth-box .form .form-control { .auth-box .form .form-control {
height: 44px; height: 44px;
font-size: 16px; font-size: 16px;
} }
.auth-box .auth-footer { .auth-box .auth-footer {
text-align: center; text-align: center;
padding: 10px; padding: 10px;
} }
.auth-box .auth-footer .text { .auth-box .auth-footer .text {
color: #777; color: #777;
} }
.auth-box .auth-footer .links a { .auth-box .auth-footer .links a {
color: #1e94cc; color: #1e94cc;
} }
.auth-box .auth-footer .links a:hover { .auth-box .auth-footer .links a:hover {
color: #1e94cc; color: #1e94cc;
} }
@ -314,6 +332,7 @@ h6 {
.auth-box.sign-up { .auth-box.sign-up {
padding-bottom: 5px; padding-bottom: 5px;
} }
.auth-box.sign-up .form { .auth-box.sign-up .form {
padding: 15px 20px 0 20px; padding: 15px 20px 0 20px;
} }
@ -325,6 +344,7 @@ h6 {
line-height: 30px; line-height: 30px;
font-family: 'Lato' !important; font-family: 'Lato' !important;
} }
.sign-up-message a { .sign-up-message a {
font-size: 18px; font-size: 18px;
color: #1e94cc !important; color: #1e94cc !important;
@ -353,38 +373,47 @@ h6 {
ul.banner-social-buttons > li:last-child { ul.banner-social-buttons > li:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
.auth-box .form { .auth-box .form {
padding: 15px 0px 0 0; padding: 15px 0px 0 0;
} }
.auth-box.sign-up .form { .auth-box.sign-up .form {
padding: 15px 0px 0 0; padding: 15px 0px 0 0;
} }
.auth-box .form .form-control { .auth-box .form .form-control {
height: 44px; height: 44px;
font-size: 13px; font-size: 13px;
} }
.auth-container .auth-title { .auth-container .auth-title {
display: none; display: none;
} }
} }
@media (max-width: 540px) { @media (max-width: 540px) {
.auth-container .auth-title h2 { .auth-container .auth-title h2 {
font-size: 32px; font-size: 32px;
width: 90%; width: 90%;
margin-bottom: 50px; margin-bottom: 50px;
} }
.auth-container.auth-signup .auth-title h2 { .auth-container.auth-signup .auth-title h2 {
font-size: 20px; font-size: 20px;
width: 90%; width: 90%;
margin-bottom: 50px; margin-bottom: 50px;
} }
.auth-box .form { .auth-box .form {
width: 90%; width: 90%;
} }
.auth-box .section-heading { .auth-box .section-heading {
font-size: 15px; font-size: 15px;
} }
} }
footer { footer {
padding: 2%; padding: 2%;
background-color: #f8f8f8; background-color: #f8f8f8;
@ -418,3 +447,231 @@ a.unlink:hover {
color: inherit; color: inherit;
} }
/***** DCL payment page **********/
.dcl-order-container {
font-family: Lato;
}
.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-order-table-total .tbl-total {
text-align: center;
color: #000;
}
.tbl-no-padding {
padding: 0px;
}
.dcl-billing-sec {
margin-top: 50px;
}
.dcl-order-sec {
padding: 0 30px;
}
.card-warning-content {
font-family: Lato;
border: 1px solid #a1a1a1;
border-radius: 3px;
padding: 5px;
}
.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;
}
.brand {
}
.brand #brand-icon {
}
.card-number-element {
}
.card-expiry-element {
}
.card-cvc-element label {
padding-left: 10px;
}
.card-element {
margin-bottom: 10px;
padding: 0;
}
.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;
}
.brand {
}
.card-expiry-element {
padding-right: 10px;
}
.card-cvc-element {
padding-left: 10px;
}
.hide-mobile{
display:none;
}
#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: 50px;
border-right: 1px solid #eee;
}
.dcl-creditcard {
padding-left: 50px;
}
.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;
}
}
@media only screen and (max-width: 1330px) and (min-width: 1200px) {
.content-dashboard {
width: 100% !important;
}
}

View file

@ -1,8 +1,27 @@
var cardBrandToPfClass = {
'visa': 'pf-visa',
'mastercard': 'pf-mastercard',
'amex': 'pf-american-express',
'discover': 'pf-discover',
'diners': 'pf-diners',
'jcb': 'pf-jcb',
'unknown': 'pf-credit-card'
};
function setBrandIcon(brand) {
var brandIconElement = document.getElementById('brand-icon');
var pfClass = 'pf-credit-card';
if (brand in cardBrandToPfClass) {
pfClass = cardBrandToPfClass[brand];
}
for (var i = brandIconElement.classList.length - 1; i >= 0; i--) {
brandIconElement.classList.remove(brandIconElement.classList[i]);
}
brandIconElement.classList.add('pf');
brandIconElement.classList.add(pfClass);
}
$(document).ready(function () { $(document).ready(function () {
$.ajaxSetup({ $.ajaxSetup({
beforeSend: function (xhr, settings) { beforeSend: function (xhr, settings) {
function getCookie(name) { function getCookie(name) {
@ -20,6 +39,7 @@ $( document ).ready(function() {
} }
return cookieValue; return cookieValue;
} }
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) { if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally. // Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
@ -31,9 +51,93 @@ $( document ).ready(function() {
var hasCreditcard = window.hasCreditcard || false; var hasCreditcard = window.hasCreditcard || false;
if (!hasCreditcard) { if (!hasCreditcard) {
var stripe = Stripe(window.stripeKey); var stripe = Stripe(window.stripeKey);
var elements = stripe.elements({locale: window.current_lan}); var element_style = {
var card = elements.create('card', options={hidePostalCode: true}); fonts: [{
card.mount('#card-element'); family: 'lato-light',
src: 'url(https://cdn.jsdelivr.net/font-lato/2.0/Lato/Lato-Light.woff) format("woff2")'
}, {
family: 'lato-regular',
src: 'url(https://cdn.jsdelivr.net/font-lato/2.0/Lato/Lato-Regular.woff) format("woff2")'
}
],
locale: window.current_lan
};
var elements = stripe.elements(element_style);
var credit_card_text_style = {
base: {
iconColor: '#666EE8',
color: '#31325F',
lineHeight: '25px',
fontWeight: 300,
fontFamily: "'lato-light', sans-serif",
fontSize: '14px',
'::placeholder': {
color: '#777'
}
},
invalid: {
iconColor: '#eb4d5c',
color: '#eb4d5c',
lineHeight: '25px',
fontWeight: 300,
fontFamily: "'lato-regular', sans-serif",
fontSize: '14px',
'::placeholder': {
color: '#eb4d5c',
fontWeight: 400
}
}
};
var credit_card_cvv_style = {
base: {
iconColor: '#666EE8',
color: '#31325F',
lineHeight: '25px',
fontWeight: 300,
fontFamily: "'lato-regular', sans-serif",
fontSize: '14px',
'::placeholder': {
color: '#555'
}
},
invalid: {
iconColor: '#eb4d5c',
color: '#eb4d5c',
lineHeight: '25px',
fontWeight: 300,
fontFamily: "'lato-regular', sans-serif",
fontSize: '14px',
'::placeholder': {
color: '#eb4d5c',
fontWeight: 600
}
}
};
var enter_ccard_text = "Enter your credit card number";
if (typeof window.enter_your_card_text !== 'undefined') {
enter_ccard_text = window.enter_your_card_text;
}
var cardNumberElement = elements.create('cardNumber', {
style: credit_card_text_style,
placeholder: enter_ccard_text
});
cardNumberElement.mount('#card-number-element');
var cardExpiryElement = elements.create('cardExpiry', {
style: credit_card_text_style
});
cardExpiryElement.mount('#card-expiry-element');
var cardCvcElement = elements.create('cardCvc', {
style: credit_card_text_style
});
cardCvcElement.mount('#card-cvc-element');
cardNumberElement.on('change', function (event) {
if (event.brand) {
setBrandIcon(event.brand);
}
});
} }
console.log("has creditcard", hasCreditcard); console.log("has creditcard", hasCreditcard);
// hasCreditcard= true; // hasCreditcard= true;
@ -52,63 +156,36 @@ $( document ).ready(function() {
} }
var $form_new = $('#payment-form-new');
$form_new.submit(payWithStripe_new);
var $form = $('#payment-form'); function payWithStripe_new(e) {
$form.submit(payWithStripe);
/* If you're using Stripe for payments */
function payWithStripe(e) {
e.preventDefault(); e.preventDefault();
function stripeTokenHandler(token) { function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server // Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form'); var form = document.getElementById('payment-form-new');
var hiddenInput = document.createElement('input');
$('#id_token').val(token.id); $('#id_token').val(token.id);
$('#billing-form').submit(); $('#billing-form').submit();
} }
stripe.createToken(card).then(function(result) { stripe.createToken(cardNumberElement).then(function (result) {
if (result.error) { if (result.error) {
// Inform the user if there was an error // Inform the user if there was an error
var errorElement = document.getElementById('card-errors'); var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message; errorElement.textContent = result.error.message;
} else { } else {
$form.find('[type=submit]').html('Processing <i class="fa fa-spinner fa-pulse"></i>'); var process_text = "Processing";
if (typeof window.processing_text !== 'undefined') {
process_text = window.processing_text
}
$form_new.find('[type=submit]').html(process_text + ' <i class="fa fa-spinner fa-pulse"></i>');
// Send the token to your server // Send the token to your server
stripeTokenHandler(result.token); stripeTokenHandler(result.token);
} }
}); });
// /* Visual feedback */
// $form.find('[type=submit]').html('Validating <i class="fa fa-spinner fa-pulse"></i>');
// var PublishableKey = window.stripeKey;
// Stripe.setPublishableKey(PublishableKey);
// Stripe.card.createToken($form, function stripeResponseHandler(status, response) {
// if (response.error) {
// /* Visual feedback */
// $form.find('[type=submit]').html('Try again');
// /* Show Stripe errors on the form */
// $form.find('.payment-errors').text(response.error.message);
// $form.find('.payment-errors').closest('.row').show();
// } else {
// /* Visual feedback */
// $form.find('[type=submit]').html('Processing <i class="fa fa-spinner fa-pulse"></i>');
// /* Hide Stripe errors on the form */
// $form.find('.payment-errors').closest('.row').hide();
// $form.find('.payment-errors').text("");
// // response contains id and card, which contains additional card details
// var token = response.id;
// // AJAX
// //set token on a hidden input
// $('#id_token').val(token);
// $('#billing-form').submit();
// }
// });
} }
/* Form validation */ /* Form validation */
@ -120,7 +197,7 @@ $( document ).ready(function() {
return this.optional(element) || /^[0-9]{2}$/.test(value); return this.optional(element) || /^[0-9]{2}$/.test(value);
}, "Please specify a valid 2-digit year."); }, "Please specify a valid 2-digit year.");
validator = $form.validate({ validator = $form_new.validate({
rules: { rules: {
cardNumber: { cardNumber: {
required: true, required: true,
@ -150,18 +227,6 @@ $( document ).ready(function() {
$(element).closest('.form-group').append(error); $(element).closest('.form-group').append(error);
} }
}); });
paymentFormReady = function() {
if ($form.find('[name=cardNumber]').hasClass("success") &&
$form.find('[name=expMonth]').hasClass("success") &&
$form.find('[name=expYear]').hasClass("success") &&
$form.find('[name=cvCode]').val().length > 1) {
return true;
} else {
return false;
}
};
// $form.find('[type=submit]').prop('disabled', true); // $form.find('[type=submit]').prop('disabled', true);
// var readyInterval = setInterval(function() { // var readyInterval = setInterval(function() {
// if (paymentFormReady()) { // if (paymentFormReady()) {

View file

@ -24,15 +24,7 @@
</div> </div>
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-12 col-md-6 pull-right text-left">
<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}}.
</address>
</div>
<div class="col-xs-6 text-right">
<address> <address>
<strong>{% trans "Date"%}:</strong><br> <strong>{% trans "Date"%}:</strong><br>
<span id="order-created_at">{{order.created_at|date:'Y-m-d H:i'}}</span><br><br> <span id="order-created_at">{{order.created_at|date:'Y-m-d H:i'}}</span><br><br>
@ -44,6 +36,15 @@
</address> </address>
</div> </div>
<div class="col-xs-12 col-md-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}}.
</address>
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">

View file

@ -2,39 +2,56 @@
{% load staticfiles bootstrap3 i18n %} {% load staticfiles bootstrap3 i18n %}
{% block content %} {% block content %}
<!-- Credit card form --> <!-- Credit card form -->
<div> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paymentfont/1.1.2/css/paymentfont.min.css"/>
<div class="dcl-order-container">
<div class="payment-container"> <div class="payment-container">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-offset-2 col-md-4 summary-box"> <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 dcl-order-sec">
<form role="form" novalidate> <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>
</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}} 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-6 col-md-6 col-lg-6"></div>
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 tbl-total">{{request.session.specs.price}}
CHF
</div>
</div>
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 dcl-billing-sec">
<h3><b>{%trans "Billing Amount" %}</b></h3> <div class="col-xs-12 col-sm-5 col-md-6 billing dcl-billing">
<hr>
<div class="content">
<!-- <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.location_code}}</span></p> -->
<!-- <hr> -->
<p><b>{%trans "Cores"%}</b> <span
class="pull-right">{{request.session.specs.cpu|floatformat}}</span></p>
<hr>
<p><b>{%trans "Memory"%}</b> <span
class="pull-right">{{request.session.specs.memory|floatformat}} GB</span></p>
<hr>
<p><b>{%trans "Disk space"%}</b> <span
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>
<h4>Total<p
class="pull-right"><b>{{request.session.specs.price }} CHF</b></p></h4>
</div>
</div>
</div>
</form>
</div>
<div class="col-xs-12 col-md-4 billing">
<h3><b>{%trans "Billing Address"%}</b></h3> <h3><b>{%trans "Billing Address"%}</b></h3>
<hr> <hr>
<form role="form" id="billing-form" method="post" action="" novalidate> <form role="form" id="billing-form" method="post" action="" novalidate>
@ -45,15 +62,18 @@
{% bootstrap_form_errors form type='non_fields'%} {% bootstrap_form_errors form type='non_fields'%}
</form> </form>
</div> </div>
</div> <div class="col-xs-12 col-sm-7 col-md-6 creditcard-box dcl-creditcard">
<div class="row">
<div class="col-xs-12 col-md-offset-2 col-md-4 "></div>
<div class="col-xs-12 col-md-4 creditcard-box">
<h3><b>{%trans "Credit Card"%}</b></h3> <h3><b>{%trans "Credit Card"%}</b></h3>
<hr> <hr>
<div> <div>
<div> <div>
<p> {% trans '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.' %}</p> <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> </div>
<br> <br>
<div> <div>
@ -64,43 +84,67 @@
<h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5> <h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5>
<input type="hidden" name="credit_card_needed" value="false"/> <input type="hidden" name="credit_card_needed" value="false"/>
</form> </form>
<div class="row"> <div class="row">
<br> <div class="col-xs-12">
<div class="col-xs-12> <p>
<p style="font-family: Lato;border: 1px solid #a1a1a1;border-radius: 3px; padding: 5px; ">{% trans "You are not making any payment yet. After submitting your card information, you will be taken to the Confirm Order Page." %}</p> {% blocktrans %}
You are not making any payment yet. After submitting your card
information, you will be taken to the Confirm Order Page.
{% endblocktrans %}
</p>
</div> </div>
<div class="col-xs-12"> <div class="col-xs-12">
<div class="col-xs-6 pull-right"> <div class="col-xs-6 pull-right">
<button style="width: 100px; float: right; font-style: normal; font-weight: bold; position: absolute; right: 0;" id="payment_button_with_creditcard" class="btn btn-success" type="submit"> <button id="payment_button_with_creditcard" class="btn btn-success stripe-payment-btn"
type="submit">
{%trans "Submit" %} {%trans "Submit" %}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
{% else %} {% else %}
<form action="" id="payment-form-new" method="POST">
<input type="hidden" name="token"/>
<form role="form" id="payment-form" novalidate> <div class="group">
<div class="row"> <div class="col-xs-12 col-sm-12 col-md-10 col-lg-9 credit-card-goup">
<div class="form-group col-xs-12"> <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 card-element card-number-element">
<div id="card-element"> <label>{%trans "Card Number" %}</label>
<!-- a Stripe Element will be inserted here. --> <div id="card-number-element" class="field my-input"></div>
</div>
<div class="col-xs-5 col-sm-3 col-md-3 col-lg-3 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-12 col-sm-2 col-md-6 col-lg-7 hide-mobile"></div>
<div class="col-xs-3 col-sm-3 col-md-3 col-lg-2 card-element card-cvc-element">
<label>{%trans "CVC" %}</label>
<div id="card-cvc-element" class="field my-input"></div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 card-element brand">
<label>{%trans "Card Type" %}</label>
<i class="pf pf-credit-card" id="brand-icon"></i>
</div> </div>
</div> </div>
</div> </div>
<div id="card-errors" role="alert"></div> <div id="card-errors" role="alert"></div>
<div class="row"> <div class="row">
<br>
<div class="col-xs-12"> <div class="col-xs-12">
<p style="font-family: Lato;border: 1px solid #a1a1a1;border-radius: 3px; padding: 5px;"> {% trans "You are not making any payment yet. After submitting your card information, you will be taken to the Confirm Order Page." %}</p> <p class="card-warning-content">
{% blocktrans %}
You are not making any payment yet. After submitting your card
information, you will be taken to the Confirm Order Page.
{% endblocktrans %}
</p>
</div> </div>
<div class="col-xs-12"> <div class="col-xs-12">
<div class="col-xs-6 pull-right"> <div class="col-xs-6 pull-right">
<button style="width: 100px; float: right; font-style: normal; font-weight: bold; position: absolute; right: 0;" class="btn btn-success" type="submit">{% trans "Submit" %}</button> <button class="btn btn-success stripe-payment-btn" type="submit">{%trans "Submit" %}
</button>
</div> </div>
</div> </div>
</div> </div>
<div class="row" style="display:none;"> <div class="row" style="display:none;">
<div class="col-xs-12"> <div class="col-xs-12">
<p class="payment-errors"></p> <p class="payment-errors"></p>
@ -115,24 +159,23 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
</form> </form>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
<!-- stripe key data --> <!-- stripe key data -->
{% if stripe_key %} {% if stripe_key %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript"> <script type="text/javascript">
window.processing_text = '{%trans "Processing" %}';
window.enter_your_card_text = '{%trans "Enter your credit card number" %}';
(function () { (function () {
window.stripeKey = "{{stripe_key}}"; window.stripeKey = "{{stripe_key}}";
@ -143,7 +186,9 @@
{% if credit_card_data.last4 and credit_card_data.cc_brand %} {% if credit_card_data.last4 and credit_card_data.cc_brand %}
<script type="text/javascript"> <script type="text/javascript">
(function () {window.hasCreditcard = true;})(); (function () {
window.hasCreditcard = true;
})();
</script> </script>
{%endif%} {%endif%}

View file

@ -440,6 +440,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
form_kwargs.update({ form_kwargs.update({
'initial': { 'initial': {
'cardholder_name': current_billing_address.cardholder_name,
'street_address': current_billing_address.street_address, 'street_address': current_billing_address.street_address,
'city': current_billing_address.city, 'city': current_billing_address.city,
'postal_code': current_billing_address.postal_code, 'postal_code': current_billing_address.postal_code,

View file

@ -5,11 +5,12 @@ from django.core.mail import EmailMultiAlternatives
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from membership.models import CustomUser from membership.models import CustomUser
# from utils.fields import CountryField # from utils.fields import CountryField
class SignupFormMixin(forms.ModelForm): class SignupFormMixin(forms.ModelForm):
confirm_password = forms.CharField(widget=forms.PasswordInput()) confirm_password = forms.CharField(widget=forms.PasswordInput())
password = forms.CharField(widget=forms.PasswordInput()) password = forms.CharField(widget=forms.PasswordInput())
@ -50,8 +51,6 @@ class LoginFormMixin(forms.Form):
return email return email
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
raise forms.ValidationError("User does not exist") raise forms.ValidationError("User does not exist")
else:
return email
class PasswordResetRequestForm(forms.Form): class PasswordResetRequestForm(forms.Form):
@ -67,8 +66,6 @@ class PasswordResetRequestForm(forms.Form):
return email return email
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
raise forms.ValidationError("User does not exist") raise forms.ValidationError("User does not exist")
else:
return email
class SetPasswordForm(forms.Form): class SetPasswordForm(forms.Form):
@ -104,8 +101,9 @@ class BillingAddressForm(forms.ModelForm):
class Meta: class Meta:
model = BillingAddress model = BillingAddress
fields = ['street_address', 'city', 'postal_code', 'country'] fields = ['cardholder_name', 'street_address', 'city', 'postal_code', 'country']
labels = { labels = {
'cardholder_name': _('Cardholder Name'),
'street_address': _('Street Address'), 'street_address': _('Street Address'),
'city': _('City'), 'city': _('City'),
'postal_code': _('Postal Code'), 'postal_code': _('Postal Code'),

View file

@ -8,6 +8,7 @@ from .fields import CountryField
# Create your models here. # Create your models here.
class BaseBillingAddress(models.Model): class BaseBillingAddress(models.Model):
cardholder_name = models.CharField(max_length=100, default="")
street_address = models.CharField(max_length=100) street_address = models.CharField(max_length=100)
city = models.CharField(max_length=50) city = models.CharField(max_length=50)
postal_code = models.CharField(max_length=50) postal_code = models.CharField(max_length=50)
@ -18,7 +19,6 @@ class BaseBillingAddress(models.Model):
class BillingAddress(BaseBillingAddress): class BillingAddress(BaseBillingAddress):
def __str__(self): def __str__(self):
return self.street_address return self.street_address
@ -32,6 +32,7 @@ class UserBillingAddress(BaseBillingAddress):
def to_dict(self): def to_dict(self):
return { return {
'Cardholder Name': self.cardholder_name,
'Street Address': self.street_address, 'Street Address': self.street_address,
'City': self.city, 'City': self.city,
'Postal Code': self.postal_code, 'Postal Code': self.postal_code,