Task #9532 Handle the UI of the login and Signup pages

Task #9535 Handle the UI of the Checkout Page
This commit is contained in:
amalelshihaby 2021-07-30 08:51:35 +02:00
parent 4a0987766d
commit 94dac8110e
29 changed files with 1046 additions and 637 deletions

View file

@ -15,16 +15,32 @@ class DomainNameField(forms.CharField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(DomainNameField, self).__init__(*args, **kwargs) super(DomainNameField, self).__init__(*args, **kwargs)
class InitialRequestForm(forms.Form): class MainModelForm(ModelForm):
def __init__(self, *args, **kwargs):
super(MainModelForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
class MainForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MainForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
if (isinstance(visible.field.widget, forms.TextInput)):
visible.field.widget.attrs['class'] = 'form-control'
elif (isinstance(visible.field.widget, forms.CheckboxInput)):
visible.field.widget.attrs['class'] = 'custom-control-input'
class InitialRequestForm(MainForm):
cores = forms.IntegerField(label='CPU', min_value=1, max_value=48, initial=1) cores = forms.IntegerField(label='CPU', min_value=1, max_value=48, initial=1)
memory = forms.IntegerField(label='RAM', min_value=2, max_value=200, initial=2) memory = forms.IntegerField(label='RAM', min_value=2, max_value=200, initial=2)
storage = forms.IntegerField(label='Storage', min_value=100, max_value=10000, initial=100) storage = forms.IntegerField(label='Storage', min_value=100, max_value=10000, initial=100)
pricing_name = forms.CharField(required=True) pricing_name = forms.CharField(required=True)
class RequestHostedVMForm(InitialRequestForm): class RequestHostedVMForm(InitialRequestForm):
matrix_domain = DomainNameField(required=True) matrix_domain = DomainNameField(required=True, widget=forms.TextInput(attrs={'placeholder': 'Matrix Domain *'}))
homeserver_domain = DomainNameField(required=True) homeserver_domain = DomainNameField(required=True, widget=forms.TextInput(attrs={'placeholder': 'Homeserver Domain *'}))
webclient_domain = DomainNameField(required=True) webclient_domain = DomainNameField(required=True, widget=forms.TextInput(attrs={'placeholder': 'Webclient Domain *'}))
is_open_registration = forms.BooleanField(required=False, initial=False) is_open_registration = forms.BooleanField(required=False, initial=False)
def clean(self): def clean(self):
@ -41,7 +57,7 @@ class RequestHostedVMForm(InitialRequestForm):
return self.cleaned_data return self.cleaned_data
class BillingAddressForm(ModelForm): class BillingAddressForm(MainModelForm):
class Meta: class Meta:
model = BillingAddress model = BillingAddress
fields = ['full_name', 'street', fields = ['full_name', 'street',

View file

@ -535,6 +535,9 @@ body, html {
.bg-dark-5 { .bg-dark-5 {
background-color: #435161 !important; background-color: #435161 !important;
} }
.bg-warning-2 {
background-color: #ffe8a3;
}
hr { hr {
border-top: 1px solid rgba(16, 85, 96, 0.1); border-top: 1px solid rgba(16, 85, 96, 0.1);
@ -3521,4 +3524,14 @@ body, html {
} }
.logo img { .logo img {
width: 200px; width: 200px;
}
.errorlist {
padding-left: 0;
list-style: none;
background-color: #e41d25;
color: #fff;
}
#card-errors {
color: #e41d25;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

View file

@ -1,59 +1,18 @@
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) { function setBrandIcon(brand) {
var brandIconElement = document.getElementById('brand-icon'); var brandIconElement = document.getElementById('brand-icon');
var pfClass = 'pf-credit-card'; var pfClass = 'fa-cc-' + brand;
if (brand in cardBrandToPfClass) {
pfClass = cardBrandToPfClass[brand];
}
for (var i = brandIconElement.classList.length - 1; i >= 0; i--) { for (var i = brandIconElement.classList.length - 1; i >= 0; i--) {
brandIconElement.classList.remove(brandIconElement.classList[i]); brandIconElement.classList.remove(brandIconElement.classList[i]);
} }
brandIconElement.classList.add('pf'); brandIconElement.classList.add('fab');
brandIconElement.classList.add(pfClass); brandIconElement.classList.add(pfClass);
} }
$(document).ready(function () { $(document).ready(function () {
$.ajaxSetup({
beforeSend: function (xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
var hasCreditcard = window.hasCreditcard || false; var hasCreditcard = window.hasCreditcard || false;
if (!hasCreditcard && window.stripeKey) { if (!hasCreditcard && window.stripeKey) {
var stripe = Stripe(window.stripeKey); var stripe = Stripe(window.stripeKey);
if (window.pm_id) { if (window.pm_id == undefined) {
} else {
var element_style = { var element_style = {
fonts: [{ fonts: [{
family: 'lato-light', family: 'lato-light',
@ -120,9 +79,9 @@ $(document).ready(function () {
} }
function submitBillingForm(pmId) { function submitBillingForm(pmId) {
var billing_form = $('#billing-form'); var order_form = $('#order_form');
billing_form.append('<input type="hidden" name="id_payment_method" value="' + pmId + '" />'); order_form.append('<input type="hidden" name="id_payment_method" value="' + pmId + '" />');
billing_form.submit(); order_form.submit();
} }
var $form_new = $('#payment-form-new'); var $form_new = $('#payment-form-new');
@ -133,7 +92,6 @@ $(document).ready(function () {
e.preventDefault(); e.preventDefault();
function stripePMHandler(paymentMethod) { function stripePMHandler(paymentMethod) {
// 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
console.log(paymentMethod);
$('#id_payment_method').val(paymentMethod.id); $('#id_payment_method').val(paymentMethod.id);
submitBillingForm(paymentMethod.id); submitBillingForm(paymentMethod.id);
} }

View file

@ -0,0 +1,97 @@
{% load static i18n %} {% get_current_language as LANGUAGE_CODE %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, shrink-to-fit=no">
<link href="{% static 'matrixhosting/images/favicon.png' %}" rel="icon" />
<title>{% block head_title %}{% endblock %}</title>
<meta name="description" content="matrixhosting by ungleich" />
<meta name="author" content="ungleich glarus ag" />
<!-- Web Fonts
============================================= -->
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i' type='text/css'>
<!-- Stylesheet
============================================= -->
<link href="{% static 'matrixhosting/css/bootstrap.min.css' %}" rel="stylesheet" />
<link href="{% static 'matrixhosting/css/fontawesome-all.min.css' %}" rel="stylesheet"type="text/css"/>
<link href="{% static 'matrixhosting/css/theme.css' %}" rel="stylesheet" type="text/css"/>
<!-- Colors Css -->
</head>
<body>
{% block body %}
<!-- Preloader -->
<div id="preloader">
<div data-loader="dual-ring"></div>
</div>
<!-- Preloader End -->
<div id="main-wrapper" class="h-100">
<div class="container-fluid px-0 h-100">
<div class="row no-gutters h-100">
<!-- Welcome Text
============================================= -->
<div class="col-md-6">
<div class="hero-wrap d-flex align-items-center h-100">
<div class="hero-mask opacity-8 bg-dark"></div>
<div class="hero-bg hero-bg-scroll" style="background-image:url({% static 'matrixhosting/images/background-image.jpg' %});"></div>
<div class="hero-content mx-auto w-100 h-100 d-flex flex-column">
<div class="row no-gutters">
<div class="col-10 col-lg-9 mx-auto">
<div class="logo mt-5 mb-5 mb-md-0"> <a class="d-flex" href="{% url 'matrix:index' %}" title="MatrixHosting"><img src="{% static 'matrixhosting/images/logo-light.png' %}" alt="MatrixHosting"></a> </div>
</div>
</div>
<div class="row no-gutters my-auto">
<div class="col-10 col-lg-9 mx-auto">
<h1 class="text-11 text-white mb-4">{% trans "Welcome!" %}</h1>
<p class="text-4 text-white">{% trans "We are glad to see you!" %}</p>
<p class="text-4 text-white mb-5">{% trans "Grow your community with less effort.!" %}</p>
</div>
</div>
</div>
</div>
</div>
<!-- Welcome Text End -->
<div class="col-md-6 d-flex align-items-center">
<div class="container my-4">
<div class="row">
<div class="col-11 col-lg-9 col-xl-8 mx-auto">
{% block content %}
{% endblock %}
{% if messages %}
<div>
<strong>Messages:</strong>
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Script -->
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"
></script>
<script src="{% static 'matrixhosting/js/bootstrap.bundle.min.js' %}"></script>
<!-- Custom JS -->
{% block js_extra %} {% endblock js_extra %}
<script src="{% static 'matrixhosting/js/theme.js' %}"></script>
{% endblock %}
{% block extra_body %}
{% endblock %}
</body>
</html>

View file

@ -0,0 +1,31 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load account %}
{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %}
{% block content %}
<h1>{% trans "Confirm E-mail Address" %}</h1>
{% if confirmation %}
{% user_display confirmation.email_address.user as user_display %}
<p>{% blocktrans with confirmation.email_address.email as email %}Please confirm that <a href="mailto:{{ email }}">{{ email }}</a> is an e-mail address for user {{ user_display }}.{% endblocktrans %}</p>
<form method="post" action="{% url 'account_confirm_email' confirmation.key %}">
{% csrf_token %}
<button type="submit">{% trans 'Confirm' %}</button>
</form>
{% else %}
{% url 'account_email' as email_url %}
<p>{% blocktrans %}This e-mail confirmation link expired or is invalid. Please <a href="{{ email_url }}">issue a new e-mail confirmation request</a>.{% endblocktrans %}</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,43 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load account socialaccount %}
{% block head_title %}{% trans "Sign In" %}{% endblock %}
{% block content %}
<h3 class="font-weight-400 mb-4">Log In</h3>
<form id="loginForm" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="p-2 my-4">
{{ form.non_field_errors }}
</div>
{% endif %}
<div class="form-group">
<label for="username">{% trans "Username" %}</label>
<input type="text" class="form-control" name="login" id="username" {% if form.login.value != None %}value="{{ form.login.value }}"{% endif %} required placeholder="{% trans 'Enter Your Username' %}">
{{ form.login.errors }}
</div>
<div class="form-group">
<label for="loginPassword">{% trans "Password" %}</label>
<input type="password" class="form-control" name="password" id="loginPassword" {% if form.password.value != None %}value="{{ form.password.value }}"{% endif %} required placeholder="{% trans 'Enter Password' %}">
{{ form.password.errors }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
</div>
<div class="row">
<div class="col-sm">
<div class="form-check custom-control custom-checkbox">
<input id="remember-me" name="remember" class="custom-control-input" type="checkbox" {% if form.password.value != None %}value="{{ form.password.value }}"{% endif %}>
<label class="custom-control-label" for="remember-me">{% trans "Remember Me" %}</label>
</div>
</div>
<div class="col-sm text-right"><a class="btn-link" href="{% url 'account_reset_password' %}">{% trans "Forgot Password ?" %}</a></div>
</div>
<button class="btn btn-primary btn-block my-4" type="submit">{% trans "Login" %}</button>
</form>
<p class="text-3 text-center text-muted">{% trans "Don't have an account?" %}<a class="btn-link px-2" href="{{ signup_url }}">{% trans "Sign Up" %}</a></p>
{% endblock %}

View file

@ -0,0 +1,18 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block head_title %}{% trans "Sign Out" %}{% endblock %}
{% block content %}
<h3 class="font-weight-400 mb-4">{% trans "Sign Out" %}</h3>
<p class="text-3 text-center text-muted">{% trans 'Are you sure you want to sign out?' %}</p>
<form id="signoutForm" method="POST" action="{% url 'account_logout' %}">
{% csrf_token %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
{% endif %}
<button class="btn btn-primary btn-block my-4" type="submit">{% trans 'Sign Out' %}</button>
</form>
{% endblock %}

View file

@ -0,0 +1,29 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load account %}
{% block head_title %}{% trans "Password Reset" %}{% endblock %}
{% block content %}
{% if user.is_authenticated %}
{% include "account/snippets/already_logged_in.html" %}
{% endif %}
<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}</p>
<form id="resetForm" method="POST" action="{% url 'account_reset_password' %}" class="password_reset">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="p-2 my-4">
{{ form.non_field_errors }}
</div>
{% endif %}
{% csrf_token %}
<div class="form-group">
<label for="email">{% trans "Email" %}</label>
<input type="text" class="form-control" name="email" id="email" {% if form.email.value != None %}value="{{ form.email.value }}"{% endif %} required placeholder="{% trans 'Enter Your Email' %}">
{{ form.email.errors }}
</div>
<button class="btn btn-primary btn-block my-4" type="submit">{% trans 'Reset My Password' %}</button>
<p class="text-4 text-center text-muted">{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}</p>
</form>
{% endblock %}

View file

@ -0,0 +1,23 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block head_title %}{% trans "Change Password" %}{% endblock %}
{% block content %}
<h1>{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}</h1>
{% if token_fail %}
{% url 'account_reset_password' as passwd_reset_url %}
<p>{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a <a href="{{ passwd_reset_url }}">new password reset</a>.{% endblocktrans %}</p>
{% else %}
{% if form %}
<form method="POST" action="{{ action_url }}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="action" value="{% trans 'change password' %}"/>
</form>
{% else %}
<p>{% trans 'Your password is now changed.' %}</p>
{% endif %}
{% endif %}
{% endblock %}

View file

@ -0,0 +1,43 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load account socialaccount %}
{% block head_title %}{% trans "Sign In" %}{% endblock %}
{% block content %}
<h3 class="font-weight-400 mb-4">Log In</h3>
<form id="signup_form" method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="p-2 my-4">
{{ form.non_field_errors }}
</div>
{% endif %}
<div class="form-group">
<label for="username">{% trans "Username" %}</label>
<input type="text" class="form-control" name="username" id="username" {% if form.username.value != None %}value="{{ form.username.value }}"{% endif %} required placeholder="{% trans 'Enter Username' %}">
{{ form.username.errors }}
</div>
<div class="form-group">
<label for="email">{% trans "E-mail (optional)" %}</label>
<input type="text" class="form-control" name="email" id="email" {% if form.email.value != None %}value="{{ form.email.value }}"{% endif %} placeholder="{% trans 'Enter Email Address' %}">
{{ form.email.errors }}
</div>
<div class="form-group">
<label for="password1">{% trans "Password" %}</label>
<input type="password" class="form-control" name="password1" id="password1" {% if form.password1.value != None %}value="{{ form.password1.value }}"{% endif %} required placeholder="{% trans 'Enter Password' %}">
{{ form.password1.errors }}
</div>
<div class="form-group">
<label for="password2">{% trans "Password" %}</label>
<input type="password" class="form-control" name="password2" id="password2" {% if form.password2.value != None %}value="{{ form.password2.value }}"{% endif %} required placeholder="{% trans 'Password (again)' %}">
{{ form.password2.errors }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
</div>
<button class="btn btn-primary btn-block my-4" type="submit">{% trans "Sign Up" %}</button>
</form>
<p class="text-3 text-center text-muted">{% trans "Already have an account?" %}<a class="btn-link px-2" href="{{ login_url }}">{% trans "Login" %}</a></p>
{% endblock %}

View file

@ -54,7 +54,6 @@
></script> ></script>
<script src="{% static 'matrixhosting/js/bootstrap.bundle.min.js' %}"></script> <script src="{% static 'matrixhosting/js/bootstrap.bundle.min.js' %}"></script>
<!-- Custom JS --> <!-- Custom JS -->
<script src="{% static 'matrixhosting/js/switcher.min.js' %}"></script>
{% block js_extra %} {% endblock js_extra %} {% block js_extra %} {% endblock js_extra %}
<script src="{% static 'matrixhosting/js/theme.js' %}"></script> <script src="{% static 'matrixhosting/js/theme.js' %}"></script>
</body> </body>

View file

@ -27,15 +27,6 @@
<i class="fa fa-plus-circle right text-5 p-3" data-plus="cores" aria-hidden="true"></i> <i class="fa fa-plus-circle right text-5 p-3" data-plus="cores" aria-hidden="true"></i>
</div> </div>
</div> </div>
<div class="help-block with-errors">
{% for message in messages %}
{% if 'cores' in message.tags %}
<ul class="list-unstyled">
<li>{{ message|safe }}</li>
</ul>
{% endif %}
{% endfor %}
</div>
</div> </div>
<div class="form-group px-n4"> <div class="form-group px-n4">
<div class="input-group"> <div class="input-group">
@ -47,15 +38,6 @@
<i class="fa fa-plus-circle right text-5 p-3" data-plus="memory" aria-hidden="true"></i> <i class="fa fa-plus-circle right text-5 p-3" data-plus="memory" aria-hidden="true"></i>
</div> </div>
</div> </div>
<div class="help-block with-errors">
{% for message in messages %}
{% if 'memory' in message.tags %}
<ul class="list-unstyled">
<li>{{ message|safe }}</li>
</ul>
{% endif %}
{% endfor %}
</div>
</div> </div>
<div class="form-group px-n4"> <div class="form-group px-n4">
<div class="input-group"> <div class="input-group">
@ -67,15 +49,6 @@
<i class="fa fa-plus-circle right text-5 p-3" data-plus="storage" aria-hidden="true"></i> <i class="fa fa-plus-circle right text-5 p-3" data-plus="storage" aria-hidden="true"></i>
</div> </div>
</div> </div>
<div class="help-block with-errors">
{% for message in messages %}
{% if 'memory' in message.tags %}
<ul class="list-unstyled">
<li>{{ message|safe }}</li>
</ul>
{% endif %}
{% endfor %}
</div>
</div> </div>
<hr class="mb-1 mx-n1"> <hr class="mb-1 mx-n1">
{% if matrix_vm_pricing.discount_amount %} {% if matrix_vm_pricing.discount_amount %}

View file

@ -1,43 +1,42 @@
{% load i18n %} {% load i18n %}
<form action="" id="payment-form-new" method="POST"> <form action="" id="payment-form-new" method="POST">
<input type="hidden" name="token"/> <input type="hidden" name="token"/>
<input type="hidden" name="id_card" id="id_card" value=""/> <input type="hidden" name="id_card" id="id_card" value=""/>
<div class="group"> <div class="group">
<div class="credit-card-goup"> <div class="credit-card-goup">
<div class="card-element card-number-element"> <div class="card-element card-number-element form-group">
<label>{%trans "Card Number" %}</label> <label>{%trans "Card Number" %}</label>
<div id="card-number-element" class="field my-input"></div> <div id="card-number-element" class="field my-input form-control"></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>
<div class="col-xs-3 col-xs-offset-4 card-element card-cvc-element"> <div class="row">
<label>{%trans "CVC" %}</label> <div class="card-element card-expiry-element col-md-6 form-group">
<div id="card-cvc-element" class="field my-input"></div> <label>{%trans "Expiry Date" %}</label>
<div id="card-expiry-element" class="field my-input form-control"></div>
</div>
<div class="card-element card-cvc-element col-md-6">
<label>{%trans "CVC" %}</label>
<div id="card-cvc-element" class="field my-input form-control"></div>
</div>
</div>
<div class="card-element brand text-6">
<i class="fab fa-credit-card" id="brand-icon"></i>
</div> </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> <div id="card-errors"></div>
<div id="card-errors"></div> <div id='payment_error'>
<div id='payment_error'> {% for message in messages %}
{% for message in messages %} {% if 'failed_payment' in message.tags or 'make_charge_error' in message.tags or 'error' in message.tags %}
{% if 'failed_payment' in message.tags or 'make_charge_error' in message.tags or 'error' in message.tags %} <ul class="list-unstyled">
<ul class="list-unstyled"> <li><p class="card-warning-content card-warning-error">{{ message|safe }}</p></li>
<li><p class="card-warning-content card-warning-error">{{ message|safe }}</p></li> </ul>
</ul> {% endif %}
{% endif %} {% endfor %}
{% endfor %} </div>
</div> <div class="text-right">
<div class="text-right"> <button class="btn btn-vm-contact btn-primary btn-wide" type="submit" name="payment-form">{%trans "Checkout" %}</button>
<button class="btn btn-vm-contact btn-wide" type="submit" name="payment-form">{%trans "SUBMIT" %}</button> </div>
</div> <div style="display:none;">
<div style="display:none;"> <p class="payment-errors"></p>
<p class="payment-errors"></p> </div>
</div> </form>
</form>

View file

@ -20,8 +20,14 @@
<div id="header-nav" class="collapse navbar-collapse"> <div id="header-nav" class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li><a href="{% url 'matrix:index' %}">Home</a></li> <li><a href="{% url 'matrix:index' %}">Home</a></li>
{% if not request.user.is_authenticated %}
<li><a href="">Pricing</a></li> <li><a href="">Pricing</a></li>
<li><a href="">Contact Us</a></li> <li><a href="">Contact Us</a></li>
{% else %}
<li><a href="">Dashboard</a></li>
<li><a href="">Instances</a></li>
<li><a href="">Help</a></li>
{% endif %}
</ul> </ul>
</div> </div>
</nav> </nav>

View file

@ -21,7 +21,7 @@
============================================= --> ============================================= -->
<div id="content"> <div id="content">
<!-- Send/Request Money <!-- calculator
============================================= --> ============================================= -->
<section class="hero-wrap"> <section class="hero-wrap">
<div class="hero-mask opacity-6 bg-dark"></div> <div class="hero-mask opacity-6 bg-dark"></div>
@ -41,7 +41,7 @@
</div> </div>
</div> </div>
</section> </section>
<!-- Send/Request Money End --> <!-- calculator -->
<!-- Why choose us <!-- Why choose us
============================================= --> ============================================= -->
@ -86,10 +86,65 @@
</div> </div>
</section> </section>
<!-- Why choose us End --> <!-- Why choose us End -->
<section class="section">
<div class="container">
<div class="row">
<div class="col-lg-6">
<div class="card bg-dark-3 shadow-sm border-0"> <img class="card-img opacity-8" src="{% static 'matrixhosting/images/matrix.jpg' %}" width="570" height="362" alt="banner">
</div>
</div>
<div class="col-lg-6 mt-5 mt-lg-0">
<div class="ml-4">
<h2 class="text-9">Growing with ease</h2>
<p class="text-4">Organise and grow your community without ethical compromises. You can start with any size you want and scale as you grow.</p>
<ul class="list-unstyled text-3 line-height-5">
<li><i class="fas fa-check mr-2"></i>Start from 40 CHF/Month</li>
<li><i class="fas fa-check mr-2"></i>No hidden Cost</li>
<li><i class="fas fa-check mr-2"></i>No limit number of users</li>
<li><i class="fas fa-check mr-2"></i>No Fossil fules</li>
</ul>
<a href="#" class="btn btn-outline-primary shadow-none mt-2">How Pricing Works</a> </div>
</div>
</div>
</div>
</section>
<section class="section bg-white">
<div class="container">
<div class="row">
<div class="col-lg-6 mt-5 mt-lg-0">
<div class="ml-4">
<h2 class="text-9">Talk to everybody via bridge while staying on Matrix</h2>
<p class="text-4">You can engage in other chat networks such as Slack, Telegram, Whatsapp, IRC, Mattermost, Rocketchat, Discord and more by <a href="https://github.com/42wim/matterbridge" target="new">Matterbridge</a>.</p>
<p class="text-4">The bridging allows you to stay on your own Matrix and receiving and sending messages to a bigger community.</p>
<a href="https://ungleich.ch/en-us/cms/matterbridge-matrix/" class="btn btn-outline-primary shadow-none mt-2">Learn more about Matterbridge</a> </div>
</div>
<div class="col-lg-6">
<div class="card border-0"> <img class="card-img" src="{% static 'matrixhosting/images/matrix-bridge-irc.jpg' %}" width="570" height="362" alt="banner">
</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="row">
<div class="col-lg-6">
<div class="card bg-dark-9"> <img class="card-img" src="{% static 'matrixhosting/images/encryption.jpeg' %}" width="570" height="362" alt="banner">
</div>
</div>
<div class="col-lg-6 mt-5 mt-lg-0">
<div class="ml-4">
<h2 class="text-9">Secure Matrix chat for your action</h2>
<p class="text-4">It's a secure chat that does not depend on a single point of failure and does not give away your data to the malicious third parties.</p>
<p class="text-4"> is <a href="https://matrix.org/blog/2020/05/06/cross-signing-and-end-to-end-encryption-by-default-is-here" target="new">End-to-End Encrypted (E2EE)</a> by default. As your communication is encrypted with multiple keys, the thrid parties can not decrypt your message, including the hosting company and the law enforcement. Your communication and community data stays private and secure.</p>
</div>
</div>
</div>
</section>
<!-- How it works <!-- How it works
============================================= --> ============================================= -->
<section class="section"> <section class="section bg-white">
<div class="container"> <div class="container">
<h2 class="text-9 text-center text-uppercase font-weight-400">As simple as 1-2-3</h2> <h2 class="text-9 text-center text-uppercase font-weight-400">As simple as 1-2-3</h2>
<p class="lead text-center mb-5">Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p> <p class="lead text-center mb-5">Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
@ -128,43 +183,46 @@
<div class="row"> <div class="row">
<div class="col-md-6 mb-4 mb-md-0"> <div class="col-md-6 mb-4 mb-md-0">
<div class="hero-wrap section h-100 p-5 rounded"> <div class="hero-wrap section h-100 p-5 rounded">
<div class="hero-mask rounded opacity-6 bg-dark"></div> <div class="hero-mask rounded opacity-7 bg-dark"></div>
<div class="hero-bg rounded" style="background-image:url({% static 'matrixhosting/images/matrix.jpg' %});"></div> <div class="hero-bg rounded" style="background-attachment: scroll;background-image:url({% static 'matrixhosting/images/renewable-energy.jpeg' %});"></div>
<div class="hero-content"> <div class="hero-content">
<h2 class="text-6 text-white mb-3">Why MatrixHosting?</h2> <h2 class="text-6 text-white mb-3">Fully Sustainable</h2>
<p class="text-light mb-5">Lisque persius interesset his et, in quot quidam persequeris vim, ad mea essent possim iriure. Mutat tacimates id sit. Ridens mediocritatem ius an, eu nec magna imperdiet.</p> <p class="text-light">MatrixHosting is a clean chat for the environment.
<h2 class="text-6 text-white mb-3">Request a matrix instance</h2> You can build and grow your community with as little carbon footprint as possible. The Matrix instance we run are hosted in <a href="https://datacenterlight.ch/" target="new">Data Center Light</a>, a Swiss datacenter built with sustainability to its core.</p>
<p class="text-light">Lisque persius interesset his et, in quot quidam persequeris vim, ad mea essent possim iriure. Mutat tacimates id sit. Ridens mediocritatem ius an, eu nec magna imperdiet.</p> <h2 class="text-6 text-white mb-3">100% Renewable Energy</h2>
<p class="text-light mb-0">Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.</p> <p class="text-light mb-0">Not every data center has an in-house hydropower plant, but we do. Data Center Light runs with 99.9%* hydropower. Few meters away from where our servers are running, the hydropower plant is generating electricity in the basement. We assure you that our electricity is made of 100% renewable energy.
*0.1 % of electricity comes from solar power. </p>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="featured-box style-1"> <div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div> <div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>Over 180 countries</h3> <h3>100% Renewable</h3>
<p>Essent lisque persius interesset his et, in quot quidam.</p> <p>Essent lisque persius interesset his et, in quot quidam.</p>
</div> </div>
<div class="featured-box style-1"> <div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div> <div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>Lower Fees</h3> <h3>100% Open Source</h3>
<p>Lisque persius interesset his et, in quot quidam persequeris.</p> <p>Lisque persius interesset his et, in quot quidam persequeris.</p>
</div> </div>
<div class="featured-box style-1"> <div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div> <div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>Easy to Use</h3> <h3>Passive Cooling</h3>
<p>Lisque persius interesset his et, in quot quidam persequeris.</p>
</div>
<div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>Reuse Hardware</h3>
<p>Essent lisque persius interesset his et, in quot quidam.</p> <p>Essent lisque persius interesset his et, in quot quidam.</p>
</div> </div>
<div class="featured-box style-1"> <div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div> <div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>Faster Payments</h3> <h3>Reuse Old Factories</h3>
<p>Quidam lisque persius interesset his et, in quot quidam.</p> <p>Quidam lisque persius interesset his et, in quot quidam.</p>
</div> </div>
<div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>100% secure</h3>
<p>Essent lisque persius interesset his et, in quot quidam.</p>
</div>
<div class="featured-box style-1"> <div class="featured-box style-1">
<div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div> <div class="featured-box-icon text-primary"> <i class="far fa-check-circle"></i> </div>
<h3>24/7 customer service</h3> <h3>24/7 customer service</h3>
@ -175,15 +233,16 @@
</div> </div>
</section> </section>
<section class="hero-wrap p-8 shadow-md" style="height: 280px;"> <section class="bg-primary opacity-7">
<div class="hero-mask opacity-3 bg-dark"></div>
<div class="hero-bg hero-bg-scrll" style="background-image:url({% static 'matrixhosting/images/how.jpg' %});"></div> <div class="hero-content py-5">
<div class="hero-content py-0 py-lg-5 my-0 my-lg-5"> <div class="container text-center">
<div class="container text-center"> <h2 class="text-9 text-white">Try it now for free</h2>
<h2 class="text-9 text-white font-weight-400 text-uppercase mb-5">How does it works? </h2> <p class="lead text-white mb-4">Want to try it before committing to a plan? You can create a free account and see how you like it. You can chat, join different rooms and invite others. You will join our actual work chat where all our team and the bigger community of Matrix users are working and chatting day and night.
<a class="video-btn d-flex" href="#" data-src="" data-toggle="modal" data-target="#videoModal"> <span class="btn-video-play bg-white shadow-md rounded-circle m-auto"><i class="fas fa-play"></i></span> </a> </div> </p>
</div> <a href="https://ungleich.ch/u/projects/open-chat/" class="btn btn-light">A free test ride on ungleich Matrix</a> </div>
</section> </div>
</section>
<!-- Testimonial <!-- Testimonial
============================================= --> ============================================= -->
@ -294,7 +353,7 @@
<hr class="mt-0"> <hr class="mt-0">
</div> </div>
</div> </div>
<div class="text-center mt-4"><a href="#" class="btn-link text-4">See more FAQ<i class="fas fa-chevron-right text-2 ml-2"></i></a></div> <div class="text-center mt-4"><a href="https://redmine.ungleich.ch/projects/open-infrastructure/wiki/Ungleich_Matrix-as-a-Service_(MaaS)" class="btn-link text-4">See more FAQ<i class="fas fa-chevron-right text-2 ml-2"></i></a></div>
</div> </div>
</section> </section>
<!-- Frequently asked questions end --> <!-- Frequently asked questions end -->

View file

@ -0,0 +1,256 @@
{% extends "matrixhosting/base.html" %}
{% load static i18n %}
{% block title %} Request Details {% endblock %}
{% block content %}
<div class="container">
<!-- Steps Progress bar -->
<div class="row mt-3 mb-4">
<div class="col-lg-12 mx-auto mb-4">
<div class="row widget-steps">
<div class="col-4 step disabled">
<div class="step-name">{%trans "Details" %}</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<a href="#" class="step-dot"></a> </div>
<div class="col-4 step active">
<div class="step-name">{%trans "Confirm" %}</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<a href="#" class="step-dot"></a> </div>
<div class="col-4 step ">
<div class="step-name">{%trans "Success" %}</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<a href="#" class="step-dot"></a> </div>
</div>
</div>
<div class="col-md-9 col-lg-8 col-xl-7 mx-auto">
<div id="order-detail{{order.pk}}" class="bg-white shadow-sm rounded p-4 mb-4">
{% if messages %}
<div class="alert alert-warning">
{% for message in messages %}
<span>{{ message }}</span>
{% endfor %}
</div>
{% endif %}
{% if not error %}
<div class="order-details">
<div>
<address>
<h5>{% trans "Billed To" %}</h5>
<p>
{% with request.session.billing_address_data as billing_address %}
{{billing_address.full_name}}<br>
{{billing_address.street}}, {{billing_address.postal_code}}<br>
{{billing_address.city}}, {{billing_address.country}}
{% if billing_address.vat_number %}
<br/>{% trans "VAT Number" %} {{billing_address.vat_number}}
{% if pricing.vat_country != "ch" and pricing.vat_validation_status != "not_needed" %}
{% if pricing.vat_validation_status == "verified" %}
<span class="fa fa-fw fa-check-circle" aria-hidden="true" title='{% trans "Your VAT number has been verified" %}'></span>
{% else %}
<span class="fa fa-fw fa-info-circle" aria-hidden="true" title='{% trans "Your VAT number is under validation. VAT will be adjusted, once the validation is complete." %}'></span>
{% endif %}
{% endif %}
{% endif %}
{% endwith %}
</p>
</address>
</div>
<div class="row align-items-center flex-row">
<div class="col col-sm-6">
<address>
<h5>{% trans "Billed To" %}</h5>
<p>
{% with request.session.billing_address_data as billing_address %}
{{billing_address.full_name}}<br>
{{billing_address.street}}, {{billing_address.postal_code}}<br>
{{billing_address.city}}, {{billing_address.country}}
{% if billing_address.vat_number %}
<br/>{% trans "VAT Number" %} {{billing_address.vat_number}}
{% if pricing.vat_country != "ch" and pricing.vat_validation_status != "not_needed" %}
{% if pricing.vat_validation_status == "verified" %}
<span class="fa fa-fw fa-check-circle" aria-hidden="true" title='{% trans "Your VAT number has been verified" %}'></span>
{% else %}
<span class="fa fa-fw fa-info-circle" aria-hidden="true" title='{% trans "Your VAT number is under validation. VAT will be adjusted, once the validation is complete." %}'></span>
{% endif %}
{% endif %}
{% endif %}
{% endwith %}
</p>
</address>
</div>
<div class="col col-sm-6 text-right text-2">
<h3 class="text-6 font-weight-400 {% if balance >= 0 %}text-success{%else%}text-danger{%endif%}">{{ balance }} CHF</h3>
<span class="text-muted text-3 opacity-8">{% trans "Available Balance"%}</span>
</div>
</div>
<hr>
<div>
<h5>{% trans "Order summary" %}</h5>
<p>
<strong>{% trans "Product" %}:</strong>&nbsp;
Matrix Chat Hosting
</p>
<div class="row">
<div class="col-sm-9">
<p>
<span>{% trans "Cores" %}: </span>
<strong class="pull-right">{{order.cores}}</strong>
</p>
<p>
<span>{% trans "Memory" %}: </span>
<strong class="pull-right">{{order.memory}} GB</strong>
</p>
<p>
<span>{% trans "Disk space" %}: </span>
<strong class="pull-right">{{order.storage}} GB</strong>
</p>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<p>
<strong class="text-uppercase">{% trans "Price Before VAT" %}</strong>
<strong class="pull-right">{{pricing.subtotal|floatformat:2}} CHF</strong>
</p>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><span></span></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p class="text-right"><strong class="cmf-ord-heading">{% trans "Pre VAT" %}</strong></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4 header-no-left-padding">
<p class="text-right"><strong class="cmf-ord-heading">{% trans "With VAT for" %} {{pricing.vat_country}} ({{pricing.vat_percent}}%)</strong></p>
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><span>Subtotal</span></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p><span class="pull-right" >{{pricing.subtotal|floatformat:2}} CHF</span></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4">
<p><span class="pull-right">{{pricing.price_with_vat|floatformat:2}} CHF</span></p>
</div>
</div>
{% if pricing.discount.amount > 0 %}
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><span>{{pricing.discount.name}}</span></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p><span class="pull-right">-{{pricing.discount.amount|floatformat:2}} CHF</span></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4">
<p><span class="pull-right">-{{pricing.discount.amount_with_vat|floatformat:2}} CHF</span></p>
</div>
</div>
{% endif %}
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><strong>Total</strong></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p><strong class="pull-right">{{pricing.subtotal_after_discount|floatformat:2}} CHF</strong></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4">
<p><strong class="pull-right">{{pricing.price_after_discount_with_vat|floatformat:2}} CHF</strong></p>
</div>
</div>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<strong class="text-uppercase align-center">{% trans "Your Price in Total" %}</strong>
<strong class="total-price pull-right">{{pricing.total_price|floatformat:2}} CHF</strong>
</div>
</div>
</div>
<hr class="thin-hr">
</div>
<form id="virtual_machine_create_form" action="" method="POST">
{% csrf_token %}
<div class="row">
<div class="col-sm-12">
<div class="dcl-place-order-text">{% blocktrans with vm_total_price=vm.total_price|floatformat:2 %}By clicking "Place order" you agree to our <a href="">Terms of Service</a> and this plan will charge your credit card account with {{ vm_total_price }} CHF/month{% endblocktrans %}.</div>
</div>
<div class="col-sm-12 order-confirm-btn text-right">
<button class="btn choice-btn btn-primary" id="btn-create-vm" data-toggle="modal" data-target="#createvm-modal">
{% trans "Confirm Order" %}
</button>
</div>
</div>
</form>
{% endif %}
</div>
</div>
</div>
</div>
<div class="modal fade" id="createvm-modal" tabindex="-1" role="dialog"
aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"><h5 class="createvm-modal-title">{% trans "Order Processing..." %}</h5>
</div>
<div class="modal-body">
<div class="row align-items-center flex-row">
<div class="modal-icon col col-sm-12 text-center">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
<span class="sr-only">{% trans "Processing..." %}</span>
</div>
<div class="modal-text col col-sm-12 text-center" id="createvm-modal-body">
{% trans "Hold tight, we are processing your request" %}
</div>
</div>
<div class="modal-footer mt-4">
<a id="createvm-modal-done-btn" class="btn btn-success btn-ok btn-wide sr-only sr-only-focusable" href="">{% trans "OK" %}</a>
<button id="createvm-modal-close-btn" type="button" class="btn btn-danger btn-ok btn-wide sr-only sr-only-focusable" data-dismiss="modal" aria-label="create-vm-close">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js_extra %}
{% if stripe_key %}
{% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript">
window.paymentIntentSecret = "{{payment_intent_secret}}";
var create_vm_error_message = 'Some problem encountered. Please try again later';
var pm_id = '{{id_payment_method}}';
var error_url = '{{ error_msg.redirect }}';
var success_url = '{{ success_msg.redirect }}';
window.stripeKey = "{{stripe_key}}";
window.isSubscription = ("{{is_subscription}}" === 'true');
</script>
{%endif%}
<!-- jQuery -->
<script src="https://js.stripe.com/v3/"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<!-- Custom JS -->
<script type="text/javascript" src="{% static 'matrixhosting/js/order.js' %}"></script>
{% endblock js_extra %}

View file

@ -1,266 +0,0 @@
{% load static i18n %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Matrix Hosting by ungleich">
<meta name="author" content="ungleich glarus ag">
<title>Matrix Hosting - {% block title %} made in Switzerland{% endblock %}</title>
<!-- Vendor CSS -->
<!-- Bootstrap Core CSS -->
<link href="{% static 'matrixhosting/css/bootstrap.min.css' %}" rel="stylesheet" />
<!-- External Fonts -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paymentfont/1.2.5/css/paymentfont.min.css"/>
<link href="//fonts.googleapis.com/css?family=Lato:300,400,600,700" rel="stylesheet" type="text/css">
<link href="{% static 'matrixhosting/css/hosting.css' %}" rel="stylesheet">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<script>
window.paymentIntentSecret = "{{payment_intent_secret}}";
</script>
<div id="order-detail{{order.pk}}" class="order-detail-container">
{% if messages %}
<div class="alert alert-warning">
{% for message in messages %}
<span>{{ message }}</span>
{% endfor %}
</div>
{% endif %}
{% if not error %}
<div class="dashboard-container-head">
<h1 class="dashboard-title-thin">
{% blocktrans with page_header_text=page_header_text|default:"Order" %}{{page_header_text}}{% endblocktrans %}
</h1>
</div>
<div class="order-details">
<hr>
<div>
<address>
<h4>{% trans "Billed to" %}:</h4>
<p>
{% with request.session.billing_address_data as billing_address %}
{{billing_address.full_name}}<br>
{{billing_address.street}}, {{billing_address.postal_code}}<br>
{{billing_address.city}}, {{billing_address.country}}
{% if billing_address.vat_number %}
<br/>{% trans "VAT Number" %} {{billing_address.vat_number}}
{% if pricing.vat_country != "ch" and pricing.vat_validation_status != "not_needed" %}
{% if pricing.vat_validation_status == "verified" %}
<span class="fa fa-fw fa-check-circle" aria-hidden="true" title='{% trans "Your VAT number has been verified" %}'></span>
{% else %}
<span class="fa fa-fw fa-info-circle" aria-hidden="true" title='{% trans "Your VAT number is under validation. VAT will be adjusted, once the validation is complete." %}'></span>
{% endif %}
{% endif %}
{% endif %}
{% endwith %}
</p>
</address>
</div>
<hr>
<div>
<h4>{% trans "Payment method" %}:</h4>
<p>
{{card.brand|default:_('Credit Card')}} {% trans "ending in" %} ****{{card.last4}}<br>
{% trans "Expiry" %} {{card.exp_year}}/{{card.exp_month}}<br/>
{{request.user.email}}
</p>
</div>
<hr>
<div>
<h4>{% trans "Order summary" %}</h4>
<style>
@media screen and (max-width:400px){
.header-no-left-padding {
padding-left: 0 !important;
}
}
@media screen and (max-width:767px){
.cmf-ord-heading {
font-size: 11px;
}
.order-detail-container .order-details {
font-size: 13px;
}
}
@media screen and (max-width:367px){
.cmf-ord-heading {
font-size: 11px;
}
.order-detail-container .order-details {
font-size: 12px;
}
}
</style>
<p>
<strong>{% trans "Product" %}:</strong>&nbsp;
Matrix Chat Hosting
</p>
<div class="row">
<div class="col-sm-9">
<p>
<span>{% trans "Cores" %}: </span>
<strong class="pull-right">{{order.cores}}</strong>
</p>
<p>
<span>{% trans "Memory" %}: </span>
<strong class="pull-right">{{order.memory}} GB</strong>
</p>
<p>
<span>{% trans "Disk space" %}: </span>
<strong class="pull-right">{{order.storage}} GB</strong>
</p>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<p>
<strong class="text-uppercase">{% trans "Price Before VAT" %}</strong>
<strong class="pull-right">{{pricing.subtotal|floatformat:2}} CHF</strong>
</p>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><span></span></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p class="text-right"><strong class="cmf-ord-heading">{% trans "Pre VAT" %}</strong></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4 header-no-left-padding">
<p class="text-right"><strong class="cmf-ord-heading">{% trans "With VAT for" %} {{pricing.vat_country}} ({{pricing.vat_percent}}%)</strong></p>
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><span>Subtotal</span></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p><span class="pull-right" >{{pricing.subtotal|floatformat:2}} CHF</span></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4">
<p><span class="pull-right">{{pricing.price_with_vat|floatformat:2}} CHF</span></p>
</div>
</div>
{% if pricing.discount.amount > 0 %}
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><span>{{pricing.discount.name}}</span></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p><span class="pull-right">-{{pricing.discount.amount|floatformat:2}} CHF</span></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4">
<p><span class="pull-right">-{{pricing.discount.amount_with_vat|floatformat:2}} CHF</span></p>
</div>
</div>
{% endif %}
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-4">
<p><strong>Total</strong></p>
</div>
<div class="col-md-3 col-sm-3 col-xs-4">
<p><strong class="pull-right">{{pricing.subtotal_after_discount|floatformat:2}} CHF</strong></p>
</div>
<div class="col-md-5 col-sm-5 col-xs-4">
<p><strong class="pull-right">{{pricing.price_after_discount_with_vat|floatformat:2}} CHF</strong></p>
</div>
</div>
</div>
<div class="col-sm-12">
<hr class="thin-hr">
</div>
<div class="col-sm-9">
<strong class="text-uppercase align-center">{% trans "Your Price in Total" %}</strong>
<strong class="total-price pull-right">{{pricing.total_price|floatformat:2}} CHF</strong>
</div>
</div>
</div>
<hr class="thin-hr">
</div>
<form id="virtual_machine_create_form" action="{% url 'matrix:order_details' %}" method="POST">
{% csrf_token %}
<div class="row">
<div class="col-sm-8">
<div class="dcl-place-order-text">{% blocktrans with vm_total_price=vm.total_price|floatformat:2 %}By clicking "Place order" you agree to our <a href="">Terms of Service</a> and this plan will charge your credit card account with {{ vm_total_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-bs-toggle="modal" data-bs-target="#createvm-modal">
{% trans "Place order" %}
</button>
</div>
</div>
</form>
{% endif %}
</div>
<!-- Create VM Modal -->
<div class="modal fade" id="createvm-modal" tabindex="-1" role="dialog"
aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
<div class="modal-icon">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
<span class="sr-only">{% trans "Processing..." %}</span>
</div>
<h4 class="modal-title" id="createvm-modal-title"></h4>
<div class="modal-text" id="createvm-modal-body">
{% trans "Hold tight, we are processing your request" %}
</div>
<div class="modal-footer">
<a id="createvm-modal-done-btn" class="btn btn-success btn-ok btn-wide visually-hidden" href="">{% trans "OK" %}</a>
<button id="createvm-modal-close-btn" type="button" class="btn btn-danger btn-ok btn-wide visually-hidden" data-dismiss="modal" aria-label="create-vm-close">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
</div>
<!-- / Create VM Modal -->
<script type="text/javascript">
var create_vm_error_message = 'Some problem encountered. Please try again later';
var pm_id = '{{id_payment_method}}';
var error_url = '{{ error_msg.redirect }}';
var success_url = '{{ success_msg.redirect }}';
window.stripeKey = "{{stripe_key}}";
window.isSubscription = ("{{is_subscription}}" === 'true');
</script>
<!-- jQuery -->
<script src="https://js.stripe.com/v3/"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<script src="{% static 'matrixhosting/js/bootstrap.bundle.min.js' %}"></script>
<!-- Custom JS -->
<script type="text/javascript" src="{% static 'matrixhosting/js/order.js' %}"></script>
</body>
</html>

View file

@ -0,0 +1,270 @@
{% extends "matrixhosting/base.html" %}
{% load static i18n %}
{% block title %} Request Details {% endblock %}
{% block content %}
<div class="container">
<!-- Steps Progress bar -->
<div class="row mt-3 mb-4">
<div class="col-lg-12 mx-auto mb-4">
<div class="row widget-steps">
<div class="col-4 step active">
<div class="step-name">{%trans "Details" %}</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<a href="#" class="step-dot"></a> </div>
<div class="col-4 step disabled">
<div class="step-name">{%trans "Confirm" %}</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<a href="#" class="step-dot"></a> </div>
<div class="col-4 step disabled">
<div class="step-name">{%trans "Success" %}</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<a href="#" class="step-dot"></a> </div>
</div>
</div>
<div class="col-lg-6">
<form id="order_form" method="POST" action="" data-toggle="validator" role="form" method="post">
{% csrf_token %}
<div class="row bg-white shadow-sm rounded p-3 p-4 pb-sm-4 mb-2">
<div class="container">
<h3 class="text-5 font-weight-400 mb-3 mb-sm-4">{% trans "Order Details"%}</h3>
<hr class="mx-n3 mb-4">
{% if details_form.non_field_errors %}
<div class="p-2 my-4">
{{ details_form.non_field_errors }}
</div>
{% endif %}
<div class="row">
<div class="col-12 col-sm-6">
<div class="form-group">
{{details_form.matrix_domain}}
{{ details_form.matrix_domain.errors }}
</div>
<div class="form-group">
{{details_form.homeserver_domain}}
{{ details_form.homeserver_domain.errors }}
</div>
<div class="form-group">
{{details_form.webclient_domain}}
{{ details_form.webclient_domain.errors }}
</div>
<div class="form-check custom-control custom-checkbox">
{{details_form.is_open_registration}}
<label class="custom-control-label" for="{{ details_form.is_open_registration.id_for_label}}">{% trans "Is Open registration possible?" %}</label>
{{ details_form.is_open_registration.errors }}
</div>
{{details_form.pricing_name.as_hidden}}
</div>
<div class="col-12 col-sm-6">
<div class="form-group px-n4">
<div class="input-group">
<div class="input-group-prepend"><i class="fa fa-minus-circle left text-5 p-3" data-minus="cores" aria-hidden="true"></i></div>
<input class="input-price select-number form-control" type="number" min="1" max="48" id="cores" step="1" name="cores"
{% if details_form.cores.value != None %}value="{{ details_form.cores.value }}"{% endif %} data-error="{% trans 'Please enter a value in range 1 - 48.' %}" required>
<div class="input-group-append">
<span class="input-group-text">Core</span>
<i class="fa fa-plus-circle right text-5 p-3" data-plus="cores" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="form-group px-n4">
<div class="input-group">
<div class="input-group-prepend"><i class="fa fa-minus-circle left text-5 p-3" data-minus="memory" aria-hidden="true"></i></div>
<input id="memory" class="input-price select-number form-control" type="number" min="2" max="200" name="memory"
{% if details_form.memory.value != None %}value="{{ details_form.memory.value }}"{% endif %} data-error="{% blocktrans with min_ram=min_ram %}Please enter a value in range {{min_ram}} - 200.{% endblocktrans %}" required step="1">
<div class="input-group-append">
<span class="input-group-text">{% trans "RAM" %}</span>
<i class="fa fa-plus-circle right text-5 p-3" data-plus="memory" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="form-group px-n4">
<div class="input-group">
<div class="input-group-prepend"><i class="fa fa-minus-circle left text-5 p-3" data-minus="storage" aria-hidden="true"></i></div>
<input id="storage" class="input-price select-number form-control" type="number" min="100" max="10000" step="100"
name="storage" {% if details_form.storage.value != None %}value="{{ details_form.storage.value }}"{% endif %} data-error="{% trans 'Please enter a value in range 100 - 10000.' %}" required>
<div class="input-group-append">
<span class="input-group-text">{% trans "GB" %}</span>
<i class="fa fa-plus-circle right text-5 p-3" data-plus="storage" aria-hidden="true"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row bg-white shadow-sm rounded p-3 p-4 pb-sm-2 mb-2">
<div class="">
<h3 class="text-5 font-weight-400 mb-3 mb-sm-4">{%trans "Billing Address"%}</h3>
<hr class="mx-n3 mb-4">
{% for message in messages %}
{% if 'vat_error' in message.tags %}
<ul class="list-unstyled"><li>
{{ message|safe }}
</li></ul>
{% endif %}
{% endfor %}
{% if billing_address_form.non_field_errors %}
<div class="p-2 my-4">
{{ billing_address_form.non_field_errors }}
</div>
{% endif %}
<div class="row">
<div class="col-12">
<div class="form-group">
<label for="{{ billing_address_form.full_name.id_for_label}}">{% trans "Full Name" %}</label>
{{billing_address_form.full_name}}
{{ billing_address_form.full_name.errors }}
</div>
</div>
<div class="col-12">
<div class="form-group">
<label for="{{ billing_address_form.street.id_for_label}}">{% trans "Street" %}</label>
{{billing_address_form.street}}
{{ billing_address_form.full_name.errors }}
</div>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label for="{{ billing_address_form.city.id_for_label}}">{% trans "City" %}</label>
{{billing_address_form.city}}
{{ billing_address_form.city.errors }}
</div>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label for="{{ billing_address_form.country.id_for_label}}">{% trans "Country" %}</label>
{{billing_address_form.country}}
{{ billing_address_form.country.errors }}
</div>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label for="{{ billing_address_form.postal_code.id_for_label}}">{% trans "Zip Code" %}</label>
{{billing_address_form.postal_code}}
{{ billing_address_form.postal_code.errors }}
</div>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label for="{{ billing_address_form.vat_number.id_for_label}}">{% trans "VAT Number" %}</label>
{{billing_address_form.vat_number}}
{{ billing_address_form.vat_number.errors }}
</div>
</div>
{% for field in billing_address_form %}
{% if field.html_name in 'active,owner' %}
{{ field.as_hidden }}
{% endif %}
{% endfor %}
</div>
</div>
</div>
</form>
</div>
<div class="col-lg-6">
<div class="row bg-white shadow-sm rounded p-4 ml-2 mb-2">
<div class="container">
<h3 class="text-5 font-weight-400 mb-3 mb-sm-4">{% trans "Payment Details"%}</h3>
<hr class="mx-n3 mb-3">
<div id="acount_balance">
<div class="row align-items-center flex-row">
<div class="col col-sm-6"><div class="text-14 text-light"><i class="fas fa-wallet"></i></div></div>
<div class="col col-sm-6 text-right text-2">
<h3 class="text-6 font-weight-400 {% if balance >= 0 %}text-success{%else%}text-danger{%endif%}">{{ balance }} CHF</h3>
<span class="text-muted text-3 opacity-8">{% trans "Available Balance"%}</span>
</div>
</div>
<hr class="mt-1 mx-n3">
</div>
<div class="row align-items-center flex-row">
<div class="col col-lg-6">
<h4 class="text-3 font-weight-400">{% trans "Total To Pay"%}</h4>
<small>
({% if matrix_vm_pricing.vat_inclusive %}{%trans "including VAT" %}{% else %}{%trans "excluding VAT" %}{% endif %})
</small>
{% if matrix_vm_pricing.discount_amount %}
<div class="text-muted"><span class="text-2">Discount {{matrix_vm_pricing.discount_amount}}</span><span class="text-2 p-1">CHF</span></div>
{% endif %}
</div>
<div class="col col-lg-6">
<div class="float-right"><span class="text-4">{{request.session.pricing.total|floatformat}}</span><span class="text-2 p-1">CHF</span></div>
</div>
</div>
<hr class="mt-2 mx-n3">
{% with cards_len=cards|length %}
<p class="text-muted">
{% if cards_len > 0 %}
{% blocktrans %}Please select one of the cards that you used before or fill in your credit card information below.{% endblocktrans %}
{% else %}
{% blocktrans %}Please fill in your credit card information below.{% endblocktrans %}
{% endif %}
</p>
<div>
{% for card in cards %}
<div class="credit-card-info">
<div class="form-check py-2 custom-control custom-radio">
<input id="card-{{card.id}}" name="payment_card" class="custom-control-input" type="radio" value="{{card.id}}">
<label class="custom-control-label" for="card-{{card.id}}">
<div class="featured-box style-1">
<div class="featured-box-icon text-primary text-9"> <i class="fab fa-cc-visa"></i> </div>
<div>
<h6 class="mb-0"> ***** {{card.last4}}</h6>
<p class="text-1 mb-0">{% trans "Expiry:" %} {{card.month}}/{{card.year}}</p>
</div>
</div>
</label>
</div>
</div>
{% endfor %}
{% if cards_len > 0 %}
<div class="form-check py-2 custom-control custom-radio" data-toggle="collapse" data-target="#newcard">
<input id="new-card" name="payment_card" class="custom-control-input" type="radio" value="new">
<label class="custom-control-label" for="new-card"><h6 class="mb-0">{% trans "Add New Card" %}</h6></label>
</div>
<div id="newcard" class="collapse">
<div class="card-details-box p-4 bg-light">
{% include "matrixhosting/includes/_card.html" %}
</div>
</div>
{% else%}
{% include "matrixhosting/includes/_card.html" %}
{% endif %}
</div>
{% endwith %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js_extra %}
{% if stripe_key %}
{% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript">
window.processing_text = '{%trans "Processing" %}';
window.enter_your_card_text = '{%trans "Enter your credit card number" %}';
(function () {
window.stripeKey = "{{stripe_key}}";
window.current_lan = "{{LANGUAGE_CODE}}";
})();
</script>
{%endif%}
<!-- jQuery -->
<script src="https://js.stripe.com/v3/"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<!-- Custom JS -->
<script type="text/javascript" src="{% static 'matrixhosting/js/payment.js' %}"></script>
{% endblock js_extra %}

View file

@ -1,166 +0,0 @@
{% load static i18n %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Matrix Hosting by ungleich">
<meta name="author" content="ungleich glarus ag">
<title>Matrix Hosting - {% block title %} made in Switzerland{% endblock %}</title>
<!-- Vendor CSS -->
<!-- Bootstrap Core CSS -->
<link href="{% static 'matrixhosting/css/bootstrap.min.css' %}" rel="stylesheet" />
<!-- External Fonts -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paymentfont/1.2.5/css/paymentfont.min.css"/>
<link href="//fonts.googleapis.com/css?family=Lato:300,400,600,700" rel="stylesheet" type="text/css">
<link href="{% static 'matrixhosting/css/hosting.css' %}" rel="stylesheet">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="row">
<div class="dcl-payment-section">
<h3>{%trans "Your Order" %}</h3>
<hr class="top-hr">
<div class="dcl-payment-order">
<p>{% trans "Cores"%} <strong class="float-end">{{request.session.order.cores|floatformat}}</strong></p>
<hr>
<p>{% trans "Memory"%} <strong class="float-end">{{request.session.order.memory|floatformat}} GB</strong></p>
<hr>
<p>{% trans "Disk space"%} <strong class="float-end">{{request.session.order.storage|floatformat}} GB</strong></p>
<hr>
<p>
<strong>{%trans "Total" %}</strong>&nbsp;&nbsp;
<small>
({% if matrix_vm_pricing.vat_inclusive %}{%trans "including VAT" %}{% else %}{%trans "excluding VAT" %}{% endif %})
</small>
<strong class="float-end">{{request.session.order.subtotal|floatformat}} CHF / {% trans "Month" %}</strong>
</p>
<hr>
{% if matrix_vm_pricing.discount_amount %}
<p class="mb-0">
<strong>{{ request.session.order.discount.name }}</strong>&nbsp;&nbsp;
<strong class="float-end text-success">- {{ request.session.order.discount.amount }} CHF / {% trans "Month" %}</strong>
</p>
{% endif %}
</div>
</div>
<div class="row">
<div class="dcl-payment-section">
<h2><b>{%trans "Billing Address"%}</b></h2>
<hr class="top-hr">
{% for message in messages %}
{% if 'vat_error' in message.tags %}
<ul class="list-unstyled"><li>
{{ message|safe }}
</li></ul>
{% endif %}
{% endfor %}
<form role="form" id="billing-form" method="post" action="" novalidate>
{% csrf_token %}
{% for field in billing_address_form %}
{% if field.html_name in 'active,owner' %}
{{ field.as_hidden }}
{%else %}
{{field}}
{% endif %}
{% endfor %}
</form>
</div>
</div>
</div>
</div>
<div class="col">
<div class="dcl-payment-section">
{% with cards_len=cards|length %}
<h3><b>{%trans "Credit Card"%}</b></h3>
<hr class="top-hr">
<p>
{% if cards_len > 0 %}
{% blocktrans %}Please select one of the cards that you used before or 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 %}
{% else %}
{% 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 %}
{% endif %}
</p>
<div>
{% for card in cards %}
<div class="credit-card-info">
<div class="col-xs-6 no-padding">
<h5 class="billing-head">{% trans "Credit Card" %}</h5>
<h5 class="membership-lead">{% trans "Last" %} 4: ***** {{card.last4}}</h5>
<h5 class="membership-lead">{% trans "Type" %}: {{card.brand}}</h5>
<h5 class="membership-lead">{% trans "Expiry" %}: {{card.month}}/{{card.year}}</h5>
</div>
<div class="col-xs-6 text-right align-bottom">
<a class="btn choice-btn choice-btn-faded" href="#" data-id_card="{{card.id}}">{% trans "SELECT" %}</a>
</div>
</div>
{% endfor %}
{% if cards_len > 0 %}
<div class="new-card-head">
<div class="row">
<div class="col-xs-6">
<h4>{% trans "Add a new credit card" %}</h4>
</div>
<div class="col-xs-6 text-right new-card-button-margin">
<button data-bs-toggle="collapse" data-bs-target="#newcard" class="btn choice-btn">
<span class="fa fa-plus"></span>&nbsp;&nbsp;{% trans "NEW CARD" %}
</button>
</div>
</div>
</div>
<div id="newcard" class="collapse">
<hr class="thick-hr">
<div class="card-details-box">
<h3>{%trans "New Credit Card" %}</h3>
<hr>
{% include "matrixhosting/includes/_card.html" %}
</div>
</div>
{% else%}
{% include "matrixhosting/includes/_card.html" %}
{% endif %}
</div>
{% endwith %}
</div>
</div>
</div>
</div>
{% if stripe_key %}
{% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript">
window.processing_text = '{%trans "Processing" %}';
window.enter_your_card_text = '{%trans "Enter your credit card number" %}';
(function () {
window.stripeKey = "{{stripe_key}}";
window.current_lan = "{{LANGUAGE_CODE}}";
})();
</script>
{%endif%}
<!-- jQuery -->
<script src="https://js.stripe.com/v3/"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<script src="{% static 'matrixhosting/js/bootstrap.bundle.min.js' %}"></script>
<!-- Custom JS -->
<script type="text/javascript" src="{% static 'matrixhosting/js/payment.js' %}"></script>
</body>
</html>

View file

@ -8,8 +8,8 @@ app_name = 'matrixhosting'
urlpatterns = [ urlpatterns = [
path('pricing/<slug:name>/calculate/', PricingView.as_view(), name='pricing_calculator'), path('pricing/<slug:name>/calculate/', PricingView.as_view(), name='pricing_calculator'),
path('payment/', OrderPaymentView.as_view(), name='payment'), path('order/new/', OrderPaymentView.as_view(), name='payment'),
path('order/details/', OrderDetailsView.as_view(), name='order_details'), path('order/confirm/', OrderDetailsView.as_view(), name='order_confirmation'),
path('dashboard/', Dashboard.as_view(), name='dashboard'), path('dashboard/', Dashboard.as_view(), name='dashboard'),
path('', IndexView.as_view(), name='index'), path('', IndexView.as_view(), name='index'),
] ]

View file

@ -22,7 +22,7 @@ from uncloud_pay.models import PricingPlan
from uncloud_pay.utils import get_order_total_with_vat from uncloud_pay.utils import get_order_total_with_vat
from uncloud_pay.models import * from uncloud_pay.models import *
from uncloud_pay.utils import validate_vat_number from uncloud_pay.utils import validate_vat_number
from uncloud_pay.selectors import get_billing_address_for_user from uncloud_pay.selectors import get_billing_address_for_user, has_enough_balance, get_balance_for_user
import uncloud_pay.stripe as uncloud_stripe import uncloud_pay.stripe as uncloud_stripe
from .models import VMInstance from .models import VMInstance
from .serializers import * from .serializers import *
@ -61,13 +61,13 @@ class IndexView(FormView):
False False
) )
self.request.session['pricing'] = {'name': form.cleaned_data['pricing_name'], self.request.session['pricing'] = {'name': form.cleaned_data['pricing_name'],
'subtotal': subtotal, 'vat': vat, 'subtotal': subtotal, 'vat': vat, 'total': total,
'vat_percent': vat_percent, 'discount': discount} 'vat_percent': vat_percent, 'discount': discount}
return HttpResponseRedirect(reverse('matrix:payment')) return HttpResponseRedirect(reverse('matrix:payment'))
class OrderPaymentView(FormView): class OrderPaymentView(FormView):
template_name = 'matrixhosting/payment.html' template_name = 'matrixhosting/order_details.html'
success_url = 'matrix:order_confirmation' success_url = 'matrix:order_confirmation'
form_class = BillingAddressForm form_class = BillingAddressForm
@ -88,12 +88,17 @@ class OrderPaymentView(FormView):
) if old_active else BillingAddressForm( ) if old_active else BillingAddressForm(
initial={'active': True, 'owner': self.request.user.id} initial={'active': True, 'owner': self.request.user.id}
) )
details_form = RequestHostedVMForm(
initial=self.request.session.get('order', {})
)
customer_id = uncloud_stripe.get_customer_id_for(self.request.user) customer_id = uncloud_stripe.get_customer_id_for(self.request.user)
cards = uncloud_stripe.get_customer_cards(customer_id) cards = uncloud_stripe.get_customer_cards(customer_id)
context.update({ context.update({
'matrix_vm_pricing': PricingPlan.get_by_name(self.request.session.get('pricing', {'name': 'unknown'})['name']), 'matrix_vm_pricing': PricingPlan.get_by_name(self.request.session.get('pricing', {'name': 'unknown'})['name']),
'billing_address_form': billing_address_form, 'billing_address_form': billing_address_form,
'details_form': details_form,
'cards': cards, 'cards': cards,
'balance': get_balance_for_user(self.request.user),
'stripe_key': settings.STRIPE_PUBLIC_KEY 'stripe_key': settings.STRIPE_PUBLIC_KEY
}) })
@ -107,8 +112,15 @@ class OrderPaymentView(FormView):
if 'order' not in request.session: if 'order' not in request.session:
return HttpResponseRedirect(reverse('matrix:index')) return HttpResponseRedirect(reverse('matrix:index'))
return self.render_to_response(self.get_context_data()) return self.render_to_response(self.get_context_data())
def form_valid(self, address_form): def post(self, request, *args, **kwargs):
details_form = RequestHostedVMForm(request.POST)
billing_address_form = BillingAddressForm(request.POST)
if not details_form.is_valid() or not billing_address_form.is_valid():
context = self.get_context_data()
context.update({'details_form': details_form,
'billing_address_form': billing_address_form})
return self.render_to_response(context)
id_payment_method = self.request.POST.get('id_payment_method', None) id_payment_method = self.request.POST.get('id_payment_method', None)
self.request.session["id_payment_method"] = id_payment_method self.request.session["id_payment_method"] = id_payment_method
this_user = { this_user = {
@ -125,12 +137,11 @@ class OrderPaymentView(FormView):
if form.is_valid: if form.is_valid:
billing_address_ins = form.save() billing_address_ins = form.save()
self.request.session["billing_address_id"] = billing_address_ins.id self.request.session["billing_address_id"] = billing_address_ins.id
self.request.session['billing_address_data'] = address_form.cleaned_data self.request.session['billing_address_data'] = billing_address_form.cleaned_data
self.request.session['billing_address_data']['owner'] = self.request.user.id self.request.session['billing_address_data']['owner'] = self.request.user.id
self.request.session['user'] = this_user self.request.session['user'] = this_user
self.request.session['customer'] = customer_id self.request.session['customer'] = customer_id
vat_number = billing_address_form.cleaned_data.get('vat_number').strip()
vat_number = address_form.cleaned_data.get('vat_number').strip()
if vat_number: if vat_number:
validate_result = validate_vat_number( validate_result = validate_vat_number(
stripe_customer_id=customer_id, stripe_customer_id=customer_id,
@ -146,58 +157,56 @@ class OrderPaymentView(FormView):
reverse('matrix:payment') + '#vat_error' reverse('matrix:payment') + '#vat_error'
) )
self.request.session["vat_validation_status"] = validate_result["status"] self.request.session["vat_validation_status"] = validate_result["status"]
return HttpResponseRedirect(reverse('matrix:order_confirmation'))
return HttpResponseRedirect(reverse('matrix:order_details'))
class OrderDetailsView(DetailView): class OrderDetailsView(DetailView):
template_name = "matrixhosting/order_detail.html" template_name = "matrixhosting/order_confirmation.html"
context_object_name = "order" context_object_name = "order"
model = Order model = Order
@method_decorator(login_required) # @method_decorator(login_required)
def dispatch(self, *args, **kwargs): # def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs) # return super().dispatch(*args, **kwargs)
@cache_control(no_cache=True, must_revalidate=True, no_store=True) @cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
context = {} context = {}
if ('order' not in request.session or 'user' not in request.session): # if ('order' not in request.session or 'user' not in request.session):
return HttpResponseRedirect(reverse('matrix:index')) # return HttpResponseRedirect(reverse('matrix:index'))
if 'id_payment_method' in self.request.session: # if 'id_payment_method' in self.request.session:
card = uncloud_stripe.get_card_from_payment(self.request.user, self.request.session['id_payment_method']) # card = uncloud_stripe.get_card_from_payment(self.request.user, self.request.session['id_payment_method'])
if not card: # if not card:
return HttpResponseRedirect(reverse('matrix:payment')) # return HttpResponseRedirect(reverse('matrix:payment'))
context['card'] = card # context['card'] = card
elif 'id_payment_method' not in self.request.session or 'vat_validation_status' not in self.request.session: # elif 'id_payment_method' not in self.request.session or 'vat_validation_status' not in self.request.session:
return HttpResponseRedirect(reverse('matrix:payment')) # return HttpResponseRedirect(reverse('matrix:payment'))
specs = request.session.get('order') # specs = request.session.get('order')
pricing = request.session.get('pricing') # pricing = request.session.get('pricing')
billing_address = BillingAddress.objects.get(id=request.session.get('billing_address_id')) # billing_address = BillingAddress.objects.get(id=request.session.get('billing_address_id'))
vat_rate = VATRate.get_vat_rate(billing_address) # vat_rate = VATRate.get_vat_rate(billing_address)
vat_validation_status = "verified" if billing_address.vat_number_validated_on and billing_address.vat_number_verified else False # vat_validation_status = "verified" if billing_address.vat_number_validated_on and billing_address.vat_number_verified else False
subtotal, subtotal_after_discount, price_after_discount_with_vat, vat, vat_percent, discount = get_order_total_with_vat( # subtotal, subtotal_after_discount, price_after_discount_with_vat, vat, vat_percent, discount = get_order_total_with_vat(
specs['cores'], specs['memory'], specs['storage'], request.session['pricing']['name'], # specs['cores'], specs['memory'], specs['storage'], request.session['pricing']['name'],
vat_rate=vat_rate * 100, vat_validation_status = vat_validation_status # vat_rate=vat_rate * 100, vat_validation_status = vat_validation_status
) # )
pricing = { # pricing = {
"subtotal": subtotal, "discount": discount, "vat": vat, "vat_percent": vat_percent, # "subtotal": subtotal, "discount": discount, "vat": vat, "vat_percent": vat_percent,
"vat_country": billing_address.country.lower(), # "vat_country": billing_address.country.lower(),
"subtotal_after_discount": subtotal_after_discount, # "subtotal_after_discount": subtotal_after_discount,
"price_after_discount_with_vat": price_after_discount_with_vat # "price_after_discount_with_vat": price_after_discount_with_vat
} # }
pricing["price_with_vat"] = round(subtotal * (1 + pricing["vat_percent"] * 0.01), 2) # pricing["price_with_vat"] = round(subtotal * (1 + pricing["vat_percent"] * 0.01), 2)
discount["amount_with_vat"] = round(pricing["price_with_vat"] - pricing["price_after_discount_with_vat"], 2) # discount["amount_with_vat"] = round(pricing["price_with_vat"] - pricing["price_after_discount_with_vat"], 2)
pricing["total_price"] = pricing["price_after_discount_with_vat"] # pricing["total_price"] = pricing["price_after_discount_with_vat"]
self.request.session['total_price'] = pricing["price_after_discount_with_vat"] # self.request.session['total_price'] = pricing["price_after_discount_with_vat"]
payment_intent_response = uncloud_stripe.get_payment_intent(request.user, pricing["price_after_discount_with_vat"]) # payment_intent_response = uncloud_stripe.get_payment_intent(request.user, pricing["price_after_discount_with_vat"])
context.update({ # context.update({
'payment_intent_secret': payment_intent_response.client_secret, # 'payment_intent_secret': payment_intent_response.client_secret,
'order': specs, # 'order': specs,
'pricing': pricing, # 'pricing': pricing,
'stripe_key': settings.STRIPE_PUBLIC_KEY, # 'stripe_key': settings.STRIPE_PUBLIC_KEY,
}) # })
return render(request, self.template_name, context) return render(request, self.template_name, context)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):

1
uncloud/.gitignore vendored
View file

@ -1,3 +1,2 @@
local_settings.py local_settings.py
ldap_max_uid_file ldap_max_uid_file
.env

View file

@ -60,9 +60,6 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.sites', 'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django_extensions', 'django_extensions',
'rest_framework', 'rest_framework',
@ -77,6 +74,9 @@ INSTALLED_APPS = [
'uncloud_service', 'uncloud_service',
'opennebula', 'opennebula',
'matrixhosting', 'matrixhosting',
'allauth',
'allauth.account',
'allauth.socialaccount',
] ]
MIDDLEWARE = [ MIDDLEWARE = [