Merge pull request #56 from levivm/feature/vm_pricing
Added pagination to orders view, Created, Virtual machines booked view
This commit is contained in:
commit
ec5cecb7c3
12 changed files with 289 additions and 116 deletions
8
hosting/managers.py
Normal file
8
hosting/managers.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class VMPlansManager(models.Manager):
|
||||||
|
|
||||||
|
def active(self, user, **kwargs):
|
||||||
|
return self.select_related('hostingorder__customer__user').\
|
||||||
|
filter(hostingorder__customer__user=user, hostingorder__approved=True, **kwargs)
|
27
hosting/migrations/0012_auto_20160501_1850.py
Normal file
27
hosting/migrations/0012_auto_20160501_1850.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-05-01 18:50
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hosting', '0011_auto_20160426_0555'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='hostingorder',
|
||||||
|
name='cc_brand',
|
||||||
|
field=models.CharField(default='Visa', max_length=10),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='hostingorder',
|
||||||
|
name='last4',
|
||||||
|
field=models.CharField(default=1111, max_length=4),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,10 +2,13 @@ import json
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
from membership.models import StripeCustomer
|
from membership.models import StripeCustomer
|
||||||
from utils.models import BillingAddress
|
from utils.models import BillingAddress
|
||||||
|
|
||||||
|
from .managers import VMPlansManager
|
||||||
|
|
||||||
|
|
||||||
class RailsBetaUser(models.Model):
|
class RailsBetaUser(models.Model):
|
||||||
email = models.EmailField(unique=True)
|
email = models.EmailField(unique=True)
|
||||||
|
@ -81,6 +84,12 @@ class VirtualMachinePlan(models.Model):
|
||||||
vm_type = models.ForeignKey(VirtualMachineType)
|
vm_type = models.ForeignKey(VirtualMachineType)
|
||||||
price = models.FloatField()
|
price = models.FloatField()
|
||||||
|
|
||||||
|
objects = VMPlansManager()
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def hosting_company_name(self):
|
||||||
|
return self.vm_type.get_hosting_company_display()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, data, user):
|
def create(cls, data, user):
|
||||||
instance = cls.objects.create(**data)
|
instance = cls.objects.create(**data)
|
||||||
|
@ -88,13 +97,23 @@ class VirtualMachinePlan(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class HostingOrder(models.Model):
|
class HostingOrder(models.Model):
|
||||||
|
|
||||||
|
ORDER_APPROVED_STATUS = 'Approved'
|
||||||
|
ORDER_DECLINED_STATUS = 'Declined'
|
||||||
|
|
||||||
VMPlan = models.OneToOneField(VirtualMachinePlan)
|
VMPlan = models.OneToOneField(VirtualMachinePlan)
|
||||||
customer = models.ForeignKey(StripeCustomer)
|
customer = models.ForeignKey(StripeCustomer)
|
||||||
billing_address = models.ForeignKey(BillingAddress)
|
billing_address = models.ForeignKey(BillingAddress)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
approved = models.BooleanField(default=False)
|
approved = models.BooleanField(default=False)
|
||||||
|
last4 = models.CharField(max_length=4)
|
||||||
|
cc_brand = models.CharField(max_length=10)
|
||||||
stripe_charge_id = models.CharField(max_length=100, null=True)
|
stripe_charge_id = models.CharField(max_length=100, null=True)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def status(self):
|
||||||
|
return self.ORDER_APPROVED_STATUS if self.approved else self.ORDER_DECLINED_STATUS
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, VMPlan=None, customer=None, billing_address=None):
|
def create(cls, VMPlan=None, customer=None, billing_address=None):
|
||||||
instance = cls.objects.create(VMPlan=VMPlan, customer=customer,
|
instance = cls.objects.create(VMPlan=VMPlan, customer=customer,
|
||||||
|
@ -107,6 +126,8 @@ class HostingOrder(models.Model):
|
||||||
|
|
||||||
def set_stripe_charge(self, stripe_charge):
|
def set_stripe_charge(self, stripe_charge):
|
||||||
self.stripe_charge_id = stripe_charge.id
|
self.stripe_charge_id = stripe_charge.id
|
||||||
|
self.last4 = stripe_charge.source.last4
|
||||||
|
self.cc_brand = stripe_charge.source.brand
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
15
hosting/static/hosting/css/commons.css
Normal file
15
hosting/static/hosting/css/commons.css
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.dashboard-container {
|
||||||
|
padding-top:5%; padding-bottom: 11%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.borderless td {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.borderless thead {
|
||||||
|
}
|
||||||
|
|
||||||
|
.borderless tbody:before {
|
||||||
|
content: "-";
|
||||||
|
display: block;
|
||||||
|
color: transparent;
|
||||||
|
}
|
17
hosting/static/hosting/css/order.css
Normal file
17
hosting/static/hosting/css/order.css
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
.order-detail-container {padding-top:5%; padding-bottom: 11%;}
|
||||||
|
|
||||||
|
.order-detail-container .invoice-title h2, .invoice-title h3 {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-detail-container .table > tbody > tr > .no-line {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-detail-container .table > thead > tr > .no-line {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-detail-container .table > tbody > tr > .thick-line {
|
||||||
|
border-top: 2px solid;
|
||||||
|
}
|
5
hosting/static/hosting/css/orders.css
Normal file
5
hosting/static/hosting/css/orders.css
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.orders-container {padding-top:5%; padding-bottom: 11%;}
|
||||||
|
|
||||||
|
.orders-container .table > tbody > tr > td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
|
@ -18,6 +18,9 @@
|
||||||
<!-- Custom CSS -->
|
<!-- Custom CSS -->
|
||||||
<link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet">
|
<link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'hosting/css/payment.css' %}" rel="stylesheet">
|
<link href="{% static 'hosting/css/payment.css' %}" rel="stylesheet">
|
||||||
|
<link href="{% static 'hosting/css/orders.css' %}" rel="stylesheet">
|
||||||
|
<link href="{% static 'hosting/css/orders.css' %}" rel="stylesheet">
|
||||||
|
<link href="{% static 'hosting/css/commons.css' %}" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Custom Fonts -->
|
<!-- Custom Fonts -->
|
||||||
<link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
|
<link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
|
||||||
|
@ -49,30 +52,51 @@
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand topnav" href="#"><img src="img/logo_black.svg"></a>
|
<a class="navbar-brand topnav" href="#"><img src="{% static 'hosting/img/logo_black.svg' %}"></a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li>
|
|
||||||
<a href="{{ request.META.HTTP_REFERER }}#how">How it works</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ request.META.HTTP_REFERER }}#your">Your infrastructure</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ request.META.HTTP_REFERER }}#our">Our inftrastructure</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ request.META.HTTP_REFERER }}#price">Pricing</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ request.META.HTTP_REFERER }}#contact">Contact</a>
|
|
||||||
</li>
|
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'hosting:logout' %}"> Logout</a>
|
<a href="{% url 'hosting:virtual_machines' %}">
|
||||||
</li>
|
<i class="fa fa-server" aria-hidden="true"></i> My Virtual Machines
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'hosting:orders' %}">
|
||||||
|
<i class="fa fa-credit-card"></i> My Orders
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dropdown">
|
||||||
|
<a class="dropdown-toggle" role="button" data-toggle="dropdown" href="#">
|
||||||
|
<i class="glyphicon glyphicon-user"></i> {{request.user.name}} <span class="caret"></span></a>
|
||||||
|
<ul id="g-account-menu" class="dropdown-menu" role="menu">
|
||||||
|
<li><a href="{% url 'hosting:logout' %}"><i class="glyphicon glyphicon-lock"></i> Logout</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ request.META.HTTP_REFERER }}#how">How it works</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ request.META.HTTP_REFERER }}#your">Your infrastructure</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ request.META.HTTP_REFERER }}#our">Our inftrastructure</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ request.META.HTTP_REFERER }}#price">Pricing</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ request.META.HTTP_REFERER }}#contact">Contact</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'hosting:login' %}?next={{request.current_path}}">Login</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,55 +2,37 @@
|
||||||
{% load staticfiles bootstrap3 %}
|
{% load staticfiles bootstrap3 %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<style type="text/css">
|
<div class="container order-detail-container">
|
||||||
.invoice-title h2, .invoice-title h3 {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table > tbody > tr > .no-line {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table > thead > tr > .no-line {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table > tbody > tr > .thick-line {
|
|
||||||
border-top: 2px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="container payment-container">
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-8 col-xs-offset-2">
|
<div class="col-xs-8 col-xs-offset-2">
|
||||||
<div class="invoice-title">
|
<div class="invoice-title">
|
||||||
<h2>Invoice</h2><h3 class="pull-right">Order # {{order.id}}</h3>
|
<h2>Invoice</h2><h3 class="pull-right">Order # {{object.id}}</h3>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<address>
|
<address>
|
||||||
<h3><b>Billed To:</b></h3>
|
<h3><b>Billed To:</b></h3>
|
||||||
John Smith<br>
|
{{user.name}}<br>
|
||||||
1234 Main<br>
|
{{object.billing_address.street_address}},{{order.billing_address.postal_code}}<br>
|
||||||
Apt. 4B<br>
|
{{object.billing_address.city}}, {{object.billing_address.country}}.
|
||||||
Springfield, ST 54321
|
|
||||||
</address>
|
</address>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6 text-right">
|
<div class="col-xs-6 text-right">
|
||||||
<address>
|
<address>
|
||||||
<strong>Order Date:</strong><br>
|
<strong>Order Date:</strong><br>
|
||||||
{{order.created_at}}<br><br>
|
{{object.created_at}}<br><br>
|
||||||
|
<strong>Status:</strong><br>
|
||||||
|
<strong class="text-danger">{{object.status}}</strong><br><br>
|
||||||
</address>
|
</address>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<address>
|
<address>
|
||||||
<strong>Payment Method:</strong><br>
|
<strong>Payment Method:</strong><br>
|
||||||
{{brand}} ending **** {{last4}}<br>
|
{{object.cc_brand}} ending **** {{object.last4}}<br>
|
||||||
{{user.email}}
|
{{user.email}}
|
||||||
</address>
|
</address>
|
||||||
</div>
|
</div>
|
||||||
|
@ -63,15 +45,15 @@
|
||||||
<h3><b>Order summary</b></h3>
|
<h3><b>Order summary</b></h3>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.hosting_company_name}}</span></p>
|
<p><b>Type</b> <span class="pull-right">{{object.VMPlan.hosting_company_name}}</span></p>
|
||||||
<hr>
|
<hr>
|
||||||
<p><b>Cores</b> <span class="pull-right">{{request.session.vm_specs.cores}}</span></p>
|
<p><b>Cores</b> <span class="pull-right">{{object.VMPlan.cores}}</span></p>
|
||||||
<hr>
|
<hr>
|
||||||
<p><b>Memory</b> <span class="pull-right">{{request.session.vm_specs.memory}} GiB</span></p>
|
<p><b>Memory</b> <span class="pull-right">{{object.VMPlan.memory}} GiB</span></p>
|
||||||
<hr>
|
<hr>
|
||||||
<p><b>Disk space</b> <span class="pull-right">{{request.session.vm_specs.disk_size}} GiB</span></p>
|
<p><b>Disk space</b> <span class="pull-right">{{object.VMPlan.disk_size}} GiB</span></p>
|
||||||
<hr>
|
<hr>
|
||||||
<h4>Total<p class="pull-right"><b>{{request.session.vm_specs.final_price}} CHF</b></p></h4>
|
<h4>Total<p class="pull-right"><b>{{object.VMPlan.price}} CHF</b></p></h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,31 +1,75 @@
|
||||||
{% extends "hosting/base_short.html" %}
|
{% extends "hosting/base_short.html" %}
|
||||||
{% load staticfiles bootstrap3 %}
|
{% load staticfiles bootstrap3 %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
.borderless td {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.borderless thead {
|
||||||
|
}
|
||||||
|
|
||||||
|
.borderless tbody:before {
|
||||||
|
content: "-";
|
||||||
|
display: block;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="container payment-container">
|
<div class="container orders-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8 col-md-offset-2">
|
<div class="col-md-8 col-md-offset-2">
|
||||||
<table class="table">
|
<table class="table borderless table-hover">
|
||||||
<caption>My orders.</caption>
|
<h3><i class="fa fa-credit-card"></i> My Orders</h3>
|
||||||
|
<br/>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Amount</th>
|
<th>Amount</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for order in orders %}
|
{% for order in orders %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{{order.id}}</th>
|
<td scope="row">{{order.id}}</td>
|
||||||
<td>{{order.created_at}}</td>
|
<td>{{order.created_at}}</td>
|
||||||
<td>{{order.VMPlan.price}}</td>
|
<td>{{order.VMPlan.price}} CHF</td>
|
||||||
<td>{{order.approved}}</td>
|
<td>{% if order.approved %}
|
||||||
|
<span class="text-success strong">Approved</span>
|
||||||
|
{% else%}
|
||||||
|
<span class="text-danger strong">Declined</span>
|
||||||
|
{% endif%}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-default"><a href="{% url 'hosting:orders' order.id %}">View Detail</a></button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
{% if is_paginated %}
|
||||||
|
<div class="pagination">
|
||||||
|
<span class="page-links">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="{{request.path}}?page={{ page_obj.previous_page_number }}">previous</a>
|
||||||
|
{% endif %}
|
||||||
|
<span class="page-current">
|
||||||
|
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
||||||
|
</span>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="{{request.path}}?page={{ page_obj.next_page_number }}">next</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
56
hosting/templates/hosting/virtual_machines.html
Normal file
56
hosting/templates/hosting/virtual_machines.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{% extends "hosting/base_short.html" %}
|
||||||
|
{% load staticfiles bootstrap3 %}
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<div class="container dashboard-container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8 col-md-offset-2">
|
||||||
|
<table class="table borderless table-hover">
|
||||||
|
<h3><i class="fa fa-server" aria-hidden="true"></i> Virtual Machines</h3>
|
||||||
|
<br/>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for vm in vms %}
|
||||||
|
<tr>
|
||||||
|
<td scope="row">{{vm.id}}</td>
|
||||||
|
<td>{{vm.hosting_company_name}}</td>
|
||||||
|
<td>{{vm.price}} CHF</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-default"><a href="">View Detail</a></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if is_paginated %}
|
||||||
|
<div class="pagination">
|
||||||
|
<span class="page-links">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="{{request.path}}?page={{ page_obj.previous_page_number }}">previous</a>
|
||||||
|
{% endif %}
|
||||||
|
<span class="page-current">
|
||||||
|
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
||||||
|
</span>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="{{request.path}}?page={{ page_obj.next_page_number }}">next</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%endblock%}
|
|
@ -1,19 +1,20 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from .views import DjangoHostingView, RailsHostingView, PaymentVMView, \
|
from .views import DjangoHostingView, RailsHostingView, PaymentVMView, \
|
||||||
NodeJSHostingView, LoginView, SignupView, IndexView, \
|
NodeJSHostingView, LoginView, SignupView, IndexView, \
|
||||||
InvoiceVMView, OrdersHostingView
|
OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'index/?$', IndexView.as_view(), name='index'),
|
url(r'index/?$', IndexView.as_view(), name='index'),
|
||||||
url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'),
|
url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'),
|
||||||
url(r'nodejs/?$', NodeJSHostingView.as_view(), name='nodejshosting'),
|
url(r'nodejs/?$', NodeJSHostingView.as_view(), name='nodejshosting'),
|
||||||
url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'),
|
url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'),
|
||||||
url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
|
url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
|
||||||
url(r'invoice/?$', InvoiceVMView.as_view(), name='invoice'),
|
url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
|
||||||
url(r'orders/?$', OrdersHostingView.as_view(), name='orders'),
|
url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'),
|
||||||
url(r'login/?$', LoginView.as_view(), name='login'),
|
url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
|
||||||
|
url(r'login/?$', LoginView.as_view(), name='login'),
|
||||||
url(r'signup/?$', SignupView.as_view(), name='signup'),
|
url(r'signup/?$', SignupView.as_view(), name='signup'),
|
||||||
url(r'^logout/?$', 'django.contrib.auth.views.logout',
|
url(r'^logout/?$', 'django.contrib.auth.views.logout',
|
||||||
{'next_page': '/ungleich_page'}, name='logout')
|
{'next_page': '/ungleich_page'}, name='logout')
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,16 +2,12 @@
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.core.urlresolvers import reverse_lazy, reverse
|
from django.core.urlresolvers import reverse_lazy, reverse
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from django.views.generic import View, CreateView, FormView
|
from django.views.generic import View, CreateView, FormView, ListView, DetailView
|
||||||
from django.shortcuts import redirect
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.contrib.auth import authenticate, login
|
from django.contrib.auth import authenticate, login
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from membership.forms import PaymentForm
|
|
||||||
from membership.models import CustomUser, StripeCustomer
|
from membership.models import CustomUser, StripeCustomer
|
||||||
from utils.stripe_utils import StripeUtils
|
from utils.stripe_utils import StripeUtils
|
||||||
from utils.forms import BillingAddressForm
|
from utils.forms import BillingAddressForm
|
||||||
|
@ -21,7 +17,6 @@ from .forms import HostingUserSignupForm, HostingUserLoginForm
|
||||||
from .mixins import ProcessVMSelectionMixin
|
from .mixins import ProcessVMSelectionMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoHostingView(ProcessVMSelectionMixin, View):
|
class DjangoHostingView(ProcessVMSelectionMixin, View):
|
||||||
template_name = "hosting/django.html"
|
template_name = "hosting/django.html"
|
||||||
|
|
||||||
|
@ -217,60 +212,38 @@ class PaymentVMView(FormView):
|
||||||
'order': order.id,
|
'order': order.id,
|
||||||
'billing_address': billing_address.id
|
'billing_address': billing_address.id
|
||||||
})
|
})
|
||||||
return HttpResponseRedirect(reverse('hosting:invoice'))
|
return HttpResponseRedirect(reverse('hosting:orders', kwargs={'pk': order.id}))
|
||||||
else:
|
else:
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
class InvoiceVMView(LoginRequiredMixin, View):
|
class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
|
||||||
template_name = "hosting/invoice.html"
|
template_name = "hosting/order_detail.html"
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
model = HostingOrder
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
charge = self.request.session.get('charge')
|
|
||||||
order_id = self.request.session.get('order')
|
|
||||||
billing_address_id = self.request.session.get('billing_address')
|
|
||||||
last4 = charge.get('source').get('last4')
|
|
||||||
brand = charge.get('source').get('brand')
|
|
||||||
|
|
||||||
order = get_object_or_404(HostingOrder, pk=order_id)
|
|
||||||
billing_address = get_object_or_404(BillingAddress, pk=billing_address_id)
|
|
||||||
|
|
||||||
if not charge:
|
|
||||||
return
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'last4': last4,
|
|
||||||
'brand': brand,
|
|
||||||
'order': order,
|
|
||||||
'billing_address': billing_address,
|
|
||||||
}
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
|
|
||||||
context = self.get_context_data()
|
|
||||||
|
|
||||||
return render(request, self.template_name, context)
|
|
||||||
|
|
||||||
|
|
||||||
class OrdersHostingView(LoginRequiredMixin, View):
|
class OrdersHostingListView(LoginRequiredMixin, ListView):
|
||||||
template_name = "hosting/orders.html"
|
template_name = "hosting/orders.html"
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
context_object_name = "orders"
|
||||||
|
model = HostingOrder
|
||||||
|
paginate_by = 10
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
orders = HostingOrder.objects.filter(customer__user=user)
|
self.queryset = HostingOrder.objects.filter(customer__user=user)
|
||||||
context = {
|
return super(OrdersHostingListView, self).get_queryset()
|
||||||
'orders':orders
|
|
||||||
}
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
|
|
||||||
context = self.get_context_data()
|
|
||||||
|
|
||||||
return render(request, self.template_name, context)
|
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
|
||||||
|
template_name = "hosting/virtual_machines.html"
|
||||||
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
context_object_name = "vms"
|
||||||
|
model = VirtualMachinePlan
|
||||||
|
paginate_by = 10
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
user = self.request.user
|
||||||
|
self.queryset = VirtualMachinePlan.objects.active(user)
|
||||||
|
return super(VirtualMachinesPlanListView, self).get_queryset()
|
||||||
|
|
Loading…
Reference in a new issue