Add hosting bill view, model and urls

This commit is contained in:
Modulos 2017-05-05 14:59:11 +02:00
parent 9884eefa19
commit 2ff8b9e4a5
9 changed files with 330 additions and 3 deletions

View file

@ -5,7 +5,8 @@ from django.core.urlresolvers import reverse
from utils.mailer import BaseEmail
from .forms import HostingOrderAdminForm
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, ManageVM
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, \
ManageVM, HostingBill
from .opennebula_functions import HostingManageVMAdmin
@ -98,3 +99,4 @@ admin.site.register(HostingOrder, HostingOrderAdmin)
admin.site.register(VirtualMachineType)
admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin)
admin.site.register(ManageVM, HostingManageVMAdmin)
admin.site.register(HostingBill)

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-04-24 04:24
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hosting', '0027_auto_20160711_0210'),
]
operations = [
migrations.CreateModel(
name='ManageVMs',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
options={
'managed': False,
},
),
]

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-04-24 04:25
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hosting', '0028_managevms'),
]
operations = [
migrations.CreateModel(
name='ManageVM',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
options={
'managed': False,
},
),
]

View file

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-05-05 11:50
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import utils.mixins
class Migration(migrations.Migration):
dependencies = [
('utils', '0005_auto_20170322_1443'),
('membership', '0006_auto_20160526_0445'),
('hosting', '0029_managevm'),
]
operations = [
migrations.CreateModel(
name='HostingBill',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('billing_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='utils.BillingAddress')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='membership.StripeCustomer')),
],
options={
'permissions': (('view_hostingbill', 'View Hosting Bill'),),
},
bases=(utils.mixins.AssignPermissionsMixin, models.Model),
),
]

View file

@ -1,5 +1,6 @@
import os
import oca
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.functional import cached_property
@ -233,3 +234,18 @@ class ManageVM(models.Model):
class Meta:
managed = False
class HostingBill(AssignPermissionsMixin, models.Model):
customer = models.ForeignKey(StripeCustomer)
billing_address = models.ForeignKey(BillingAddress)
permissions = ('view_hostingbill',)
class Meta:
permissions = (
('view_hostingbill', 'View Hosting Bill'),
)
def __str__(self):
return "%s" % (self.customer.user.email)

View file

@ -0,0 +1,93 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 %}
{% load i18n %}
{% block content %}
<h1> {{ bill }} </h1>
<div class="container">
{# Adress bar #}
<div class="row">
<div class="invoice-title">
<h2>{% trans "Invoice"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{bill.id}}</h3>
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-6">
<address>
{{bill.customer.user.name}}<br>
{{bill.billing_address.street_address}},{{bill.billing_address.postal_code}}<br>
{{bill.billing_address.city}}, {{bill.billing_address.country}}.
</address>
</div>
<div class="col-sm-6 text-right">
<address>
{% trans "ungleich GmbH" %}<br>
{% trans "buchhaltung@ungleich.ch" %}<br>
{% trans "Hauptstrasse 14"%}<br>
{% trans "CH-8775 Luchsingen"%}<br>
{% trans "Mwst-Nummer: CHE-109.549.333 MWST"%}<br>
</address>
</div>
</div>
<hr>
<table class="table table-bordered">
{# Bill header #}
<thead>
<tr>
<th>Name</th>
<th>Cores</th>
<th>Memory</th>
<th>Disk Size</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{# Bill items#}
{% for vm in vms %}
<tr>
<td>{{ vm.name }}</td>
<td>{{ vm.cores }}</td>
<td>{{ vm.memory }}</td>
<td>{{ vm.disk_size }}</td>
<td>{{ vm.price }}</td>
</tr>
{% endfor %}
{# Bill total#}
<tr>
<td> {% trans "Total:" %} </td>
<td> </td>
<td> </td>
<td> {% trans "Brutto" %} </td>
<td> {% trans "Netto" %} </td>
</tr>
</tbody>
</table>
<hr>
{# Bill Footer #}
<div class="row">
{% trans "Alles Preise in CHF mit 8% Mehrwertsteuer." %}
{% trans "Betrag zahlbar innerhalb von 30 Tagen ab Rechnungseingang." %}
{% trans "Kontoverbindung:" %}
<div class="row">
<div class="col-sm-6">
{% trans "IBAN:" %}
</div>
<div class="col-sm-6">
{% trans "BIC:" %}
</div>
</div>
<div class="row">
<div class="col-sm-6">
{% trans "CH02 ............" %}
</div>
<div class="col-sm-6">
{% trans "POFICHBEXXX" %}
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,60 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 %}
{% load i18n %}
{% block content %}
<div>
<div class="container orders-container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<table class="table borderless table-hover">
<h3>{% trans "Customers"%}</h3>
<br/>
<thead>
<tr>
<th>{% trans "Name"%}</th>
<th>{% trans "Email"%}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.name}}</td>
<td>{{ user.email}} CHF</td>
<td>
<button type="button" class="btn btn-default"><a
href="{% url 'hosting:bills' user.id %}">{% trans "View Bill"%}</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 }}">{% trans "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 }}">{% trans "next"%}</a>
{% endif %}
</span>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -4,7 +4,8 @@ from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\
NodeJSHostingView, LoginView, SignupView, IndexView, \
OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, \
HostingPricingView, HostingBillListView, HostingBillDetailView
urlpatterns = [
url(r'index/?$', IndexView.as_view(), name='index'),
@ -15,6 +16,8 @@ urlpatterns = [
url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'),
url(r'bills/?$', HostingBillListView.as_view(), name='bills'),
url(r'bills/(?P<pk>\d+)/?$', HostingBillDetailView.as_view(), name='bills'),
url(r'cancel_order/(?P<pk>\d+)/?$', OrdersHostingDeleteView.as_view(), name='delete_order'),
url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(),

View file

@ -1,3 +1,4 @@
import oca
from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy, reverse
@ -19,7 +20,7 @@ from utils.stripe_utils import StripeUtils
from utils.forms import BillingAddressForm, PasswordResetRequestForm
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
from utils.mailer import BaseEmail
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, HostingBill
from .forms import HostingUserSignupForm, HostingUserLoginForm
from .mixins import ProcessVMSelectionMixin
@ -328,6 +329,10 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai
permission_required = ['view_hostingorder']
model = HostingOrder
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
print(context)
return context
class OrdersHostingListView(LoginRequiredMixin, ListView):
template_name = "hosting/orders.html"
@ -396,3 +401,72 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, UpdateView
email.send()
return HttpResponseRedirect(self.get_success_url())
class HostingBillListView(LoginRequiredMixin, ListView):
template_name = "hosting/bills.html"
login_url = reverse_lazy('hosting:login')
context_object_name = "users"
model = StripeCustomer
paginate_by = 10
ordering = '-id'
#TODO show only clients i.e. get_query_set
class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailView):
template_name = "hosting/bill_detail.html"
login_url = reverse_lazy('hosting:login')
permission_required = ['view_hostingview']
context_object_name = "bill"
model = HostingBill
def get_object(self, queryset=None):
#Get HostingBill for primary key (Select from customer users)
pk = self.kwargs['pk']
return HostingBill.objects.filter(customer__id=pk).first()
def get_context_data(self, **kwargs):
# Get User
user_email = self.object.customer.user.email
# Get context
context = super(DetailView, self).get_context_data(**kwargs)
# Add VMs to context
context['vms'] = []
# Connect to open nebula server
client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME,
settings.OPENNEBULA_PASSWORD),
"{protocol}://{domain}:{port}{endpoint}".format(
protocol=settings.OPENNEBULA_PROTOCOL,
domain=settings.OPENNEBULA_DOMAIN,
port=settings.OPENNEBULA_PORT,
endpoint=settings.OPENNEBULA_ENDPOINT
))
# Get open nebula user id for given email
user_pool = oca.UserPool(client)
user_pool.info()
user_id = user_pool.get_by_name('alain').id
# Get vm_pool for given user_id
vm_pool = oca.VirtualMachinePool(client)
vm_pool.info(filter=user_id)
# Add vm in vm_pool to context
for vm in vm_pool:
#TODO: Replace with vm plan
name = vm.name
cores = int(vm.template.vcpu)
memory = int(vm.template.memory) / 1024
# Check if vm has more than one disk
if 'DISK' in vm.template.multiple:
disk_size = 0
for disk in vm.template.disks:
disk_size += int(disk.size) / 1024
else:
disk_size = int(vm.template.disk.size) / 1024
vm = {}
vm['name'] = name
vm['price'] = 0.6 * disk_size + 2 * memory + 5 * cores
vm['disk_size'] = disk_size
vm['cores'] = cores
vm['memory'] = memory
context['vms'].append(vm)
return context