commit
				
					
						7cd2f1884d
					
				
			
		
					 12 changed files with 371 additions and 5 deletions
				
			
		| 
						 | 
					@ -5,7 +5,8 @@ from django.core.urlresolvers import reverse
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					from utils.mailer import BaseEmail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import HostingOrderAdminForm
 | 
					from .forms import HostingOrderAdminForm
 | 
				
			||||||
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, ManageVM
 | 
					from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, \
 | 
				
			||||||
 | 
					                    ManageVM, HostingBill
 | 
				
			||||||
from .opennebula_functions import HostingManageVMAdmin
 | 
					from .opennebula_functions import HostingManageVMAdmin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,3 +99,4 @@ admin.site.register(HostingOrder, HostingOrderAdmin)
 | 
				
			||||||
admin.site.register(VirtualMachineType)
 | 
					admin.site.register(VirtualMachineType)
 | 
				
			||||||
admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin)
 | 
					admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin)
 | 
				
			||||||
admin.site.register(ManageVM, HostingManageVMAdmin)
 | 
					admin.site.register(ManageVM, HostingManageVMAdmin)
 | 
				
			||||||
 | 
					admin.site.register(HostingBill)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										24
									
								
								hosting/migrations/0028_managevms.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								hosting/migrations/0028_managevms.py
									
										
									
									
									
										Normal 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,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										24
									
								
								hosting/migrations/0029_managevm.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								hosting/migrations/0029_managevm.py
									
										
									
									
									
										Normal 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,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										31
									
								
								hosting/migrations/0030_hostingbill.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								hosting/migrations/0030_hostingbill.py
									
										
									
									
									
										Normal 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),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										20
									
								
								hosting/migrations/0031_hostingbill_total_price.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								hosting/migrations/0031_hostingbill_total_price.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					# Generated by Django 1.9.4 on 2017-05-06 12:30
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('hosting', '0030_hostingbill'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='hostingbill',
 | 
				
			||||||
 | 
					            name='total_price',
 | 
				
			||||||
 | 
					            field=models.FloatField(default=0.0),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
							
								
								
									
										16
									
								
								hosting/migrations/0037_merge.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								hosting/migrations/0037_merge.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					# Generated by Django 1.9.4 on 2017-05-07 04:49
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('hosting', '0031_hostingbill_total_price'),
 | 
				
			||||||
 | 
					        ('hosting', '0036_auto_20170506_2312'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import oca
 | 
					import socket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import oca
 | 
				
			||||||
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.utils.functional import cached_property
 | 
				
			||||||
| 
						 | 
					@ -15,6 +16,7 @@ from membership.models import StripeCustomer, CustomUser
 | 
				
			||||||
from utils.models import BillingAddress
 | 
					from utils.models import BillingAddress
 | 
				
			||||||
from utils.mixins import AssignPermissionsMixin
 | 
					from utils.mixins import AssignPermissionsMixin
 | 
				
			||||||
from .managers import VMPlansManager
 | 
					from .managers import VMPlansManager
 | 
				
			||||||
 | 
					from oca.exceptions import OpenNebulaException
 | 
				
			||||||
from oca.pool import WrongNameError
 | 
					from oca.pool import WrongNameError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
| 
						 | 
					@ -314,6 +316,47 @@ class ManageVM(models.Model):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        managed = False
 | 
					        managed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HostingBill(AssignPermissionsMixin, models.Model):
 | 
				
			||||||
 | 
					    customer = models.ForeignKey(StripeCustomer)
 | 
				
			||||||
 | 
					    billing_address = models.ForeignKey(BillingAddress)
 | 
				
			||||||
 | 
					    total_price = models.FloatField(default=0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    permissions = ('view_hostingbill',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        permissions = (
 | 
				
			||||||
 | 
					            ('view_hostingbill', 'View Hosting Bill'),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return "%s" % (self.customer.user.email)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def create(cls, customer=None, billing_address=None):
 | 
				
			||||||
 | 
					        instance = cls.objects.create(customer=customer, billing_address=billing_address)
 | 
				
			||||||
 | 
					        return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_vms(self):
 | 
				
			||||||
 | 
					        email = self.customer.user.email
 | 
				
			||||||
 | 
					        # Get opennebula client
 | 
				
			||||||
 | 
					        opennebula_client = OpenNebulaManager(create_user=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Get vm pool
 | 
				
			||||||
 | 
					        vm_pool = opennebula_client.get_vms(email)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Reset total price
 | 
				
			||||||
 | 
					        self.total_price = 0
 | 
				
			||||||
 | 
					        vms = []
 | 
				
			||||||
 | 
					        # Add vm in vm_pool to context
 | 
				
			||||||
 | 
					        for vm in vm_pool:
 | 
				
			||||||
 | 
					            vm_data = OpenNebulaManager.parse_vm(vm)
 | 
				
			||||||
 | 
					            self.total_price += vm_data['price']
 | 
				
			||||||
 | 
					            vms.append(vm_data)
 | 
				
			||||||
 | 
					        self.save()
 | 
				
			||||||
 | 
					        return vms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
def get_user_opennebula_password():
 | 
					def get_user_opennebula_password():
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    TODO: Implement the way we obtain the user's opennebula password 
 | 
					    TODO: Implement the way we obtain the user's opennebula password 
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										91
									
								
								hosting/templates/hosting/bill_detail.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								hosting/templates/hosting/bill_detail.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,91 @@
 | 
				
			||||||
 | 
					{% extends "hosting/base_short.html" %}
 | 
				
			||||||
 | 
					{% load staticfiles bootstrap3 %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="container">
 | 
				
			||||||
 | 
					    <div class="orders-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><span class="pull-right">{{ vm.cores }}</span></td>
 | 
				
			||||||
 | 
					                        <td><span class="pull-right">{{ vm.memory|floatformat }} GiB </span></td>
 | 
				
			||||||
 | 
					                        <td><span class="pull-right">{{ vm.disk_size|floatformat }} GiB </span></td>
 | 
				
			||||||
 | 
					                        <td><span class="pull-right">{{ vm.price|floatformat }} CHF</span></td>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    </tr>
 | 
				
			||||||
 | 
					                {% endfor %}
 | 
				
			||||||
 | 
					                {# Bill total#}
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <td colspan=4> {% trans "Total:" %} </td>
 | 
				
			||||||
 | 
					                    <td> <span class="pull-right">{{ bill.total_price|floatformat}} CHF </span></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>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
							
								
								
									
										14
									
								
								hosting/templates/hosting/bill_error.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								hosting/templates/hosting/bill_error.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					{% extends "hosting/base_short.html" %}
 | 
				
			||||||
 | 
					{% load staticfiles bootstrap3 %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="container">
 | 
				
			||||||
 | 
					    <div class="container orders-container">
 | 
				
			||||||
 | 
					    <h1>Error</h1>
 | 
				
			||||||
 | 
					    <p> Could not get HostingBill object for client. </p>
 | 
				
			||||||
 | 
					    <p> Please create a HostingBill object via the admin page </p>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
							
								
								
									
										60
									
								
								hosting/templates/hosting/bills.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								hosting/templates/hosting/bills.html
									
										
									
									
									
										Normal 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.user.name}}</td>
 | 
				
			||||||
 | 
					                                <td>{{ user.user.email}}</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 %}
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\
 | 
				
			||||||
    OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
 | 
					    OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
 | 
				
			||||||
    VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \
 | 
					    VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \
 | 
				
			||||||
    MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView,\
 | 
					    MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView,\
 | 
				
			||||||
    CreateVirtualMachinesView
 | 
					    CreateVirtualMachinesView, HostingBillListView, HostingBillDetailView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    url(r'index/?$', IndexView.as_view(), name='index'),
 | 
					    url(r'index/?$', IndexView.as_view(), name='index'),
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,8 @@ urlpatterns = [
 | 
				
			||||||
    url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
 | 
					    url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
 | 
				
			||||||
    url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
 | 
					    url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
 | 
				
			||||||
    url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.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'cancel_order/(?P<pk>\d+)/?$', OrdersHostingDeleteView.as_view(), name='delete_order'),
 | 
				
			||||||
    url(r'create-virtual-machine/?$', CreateVirtualMachinesView.as_view(), name='create-virtual-machine'),
 | 
					    url(r'create-virtual-machine/?$', CreateVirtualMachinesView.as_view(), name='create-virtual-machine'),
 | 
				
			||||||
    url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
 | 
					    url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ from django.views.generic import View, CreateView, FormView, ListView, DetailVie
 | 
				
			||||||
    DeleteView, TemplateView, UpdateView
 | 
					    DeleteView, TemplateView, UpdateView
 | 
				
			||||||
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.contrib import messages
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.shortcuts import redirect
 | 
					from django.shortcuts import redirect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,11 +25,14 @@ from utils.stripe_utils import StripeUtils
 | 
				
			||||||
from utils.forms import BillingAddressForm, PasswordResetRequestForm
 | 
					from utils.forms import BillingAddressForm, PasswordResetRequestForm
 | 
				
			||||||
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
 | 
					from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
 | 
				
			||||||
from utils.mailer import BaseEmail
 | 
					from utils.mailer import BaseEmail
 | 
				
			||||||
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, UserHostingKey
 | 
					from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, HostingBill, UserHostingKey
 | 
				
			||||||
from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm
 | 
					from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm
 | 
				
			||||||
from .mixins import ProcessVMSelectionMixin
 | 
					from .mixins import ProcessVMSelectionMixin
 | 
				
			||||||
from .opennebula_functions import HostingManageVMAdmin, OpenNebulaManager
 | 
					from .opennebula_functions import HostingManageVMAdmin, OpenNebulaManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from oca.exceptions import OpenNebulaException
 | 
				
			||||||
 | 
					from oca.pool import WrongNameError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DjangoHostingView(ProcessVMSelectionMixin, View):
 | 
					class DjangoHostingView(ProcessVMSelectionMixin, View):
 | 
				
			||||||
    template_name = "hosting/django.html"
 | 
					    template_name = "hosting/django.html"
 | 
				
			||||||
| 
						 | 
					@ -317,6 +321,8 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
				
			||||||
            # Create a Hosting Order
 | 
					            # Create a Hosting Order
 | 
				
			||||||
            order = HostingOrder.create(vm_plan=plan, customer=customer,
 | 
					            order = HostingOrder.create(vm_plan=plan, customer=customer,
 | 
				
			||||||
                                        billing_address=billing_address)
 | 
					                                        billing_address=billing_address)
 | 
				
			||||||
 | 
					            # Create a Hosting Bill
 | 
				
			||||||
 | 
					            bill = HostingBill.create(customer=customer, billing_address=billing_address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Make stripe charge to a customer
 | 
					            # Make stripe charge to a customer
 | 
				
			||||||
            stripe_utils = StripeUtils()
 | 
					            stripe_utils = StripeUtils()
 | 
				
			||||||
| 
						 | 
					@ -378,7 +384,6 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai
 | 
				
			||||||
    permission_required = ['view_hostingorder']
 | 
					    permission_required = ['view_hostingorder']
 | 
				
			||||||
    model = HostingOrder
 | 
					    model = HostingOrder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class OrdersHostingListView(LoginRequiredMixin, ListView):
 | 
					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')
 | 
				
			||||||
| 
						 | 
					@ -532,3 +537,37 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
 | 
				
			||||||
        email.send()
 | 
					        email.send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return HttpResponseRedirect(self.get_success_url())
 | 
					        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'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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']
 | 
				
			||||||
 | 
					        object = HostingBill.objects.filter(customer__id=pk).first()
 | 
				
			||||||
 | 
					        if object is None:
 | 
				
			||||||
 | 
					            self.template_name = 'hosting/bill_error.html'
 | 
				
			||||||
 | 
					        return object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        # Get context
 | 
				
			||||||
 | 
					        context = super(DetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
 | 
					        # Get vms
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            context['vms'] = self.get_object().get_vms()
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue