Various updates

This commit is contained in:
Nico Schottelius 2020-08-09 10:14:49 +02:00
parent e169b8c1d1
commit 89519e48a9
5 changed files with 80 additions and 57 deletions

View file

@ -1,6 +1,7 @@
from django.contrib import admin from django.contrib import admin
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import path from django.urls import path
from django.shortcuts import render
from django.conf.urls import url from django.conf.urls import url
from uncloud_pay.views import BillViewSet from uncloud_pay.views import BillViewSet
@ -36,12 +37,13 @@ class BillAdmin(admin.ModelAdmin):
pat = lambda regex, fn: url(regex, self.admin_site.admin_view(fn), name='%s_%s' % (info, fn.__name__)) pat = lambda regex, fn: url(regex, self.admin_site.admin_view(fn), name='%s_%s' % (info, fn.__name__))
url_patterns = [ url_patterns = [
pat(r'^([0-9]+)/as_pdf/$', self.my_view), pat(r'^([0-9]+)/as_pdf/$', self.as_pdf),
pat(r'^([0-9]+)/as_html/$', self.as_html),
] + super().get_urls() ] + super().get_urls()
return url_patterns return url_patterns
def my_view(self, request, object_id): def as_pdf(self, request, object_id):
bill = self.get_object(request, object_id=object_id) bill = self.get_object(request, object_id=object_id)
print(bill) print(bill)
@ -59,15 +61,29 @@ class BillAdmin(admin.ModelAdmin):
return response return response
# ... def as_html(self, request, object_id):
context = dict( bill = self.get_object(request, object_id=object_id)
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
# key=value,
)
#return TemplateResponse(request, "admin/change_list.html", context) if bill is None:
raise self._get_404_exception(object_id)
return render(request, 'bill.html.j2',
{'bill': bill,
'bill_records': bill.billrecord_set.all()
})
bill_html = render_to_string("bill.html.j2", {'bill': bill,
'bill_records': bill.billrecord_set.all()
})
bytestring_to_pdf(bill_html.encode('utf-8'), output_file)
response = FileResponse(output_file, content_type="application/pdf")
response['Content-Disposition'] = f'filename="bill_{bill}.pdf"'
return HttpResponse(template.render(context, request))
return response
admin.site.register(Bill, BillAdmin) admin.site.register(Bill, BillAdmin)

View file

@ -50,47 +50,44 @@ class Command(BaseCommand):
) )
# 25206 # 25206 + SSD
vm25206 = VMProduct(name="OpenNebula 25206", vm25206 = VMProduct(name="25206", cores=1, ram_in_gb=4, owner=user)
cores=1,
ram_in_gb=4,
owner=user)
vm25206.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) vm25206.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
vm25206.save() vm25206.save()
vm25206_ssd = VMDiskProduct(vm=vm25206, vm25206_ssd = VMDiskProduct(vm=vm25206, owner=user, size_in_gb=30)
owner=user,
size_in_gb=30)
vm25206_ssd.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) vm25206_ssd.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
vm25206_ssd.save() vm25206_ssd.save()
# change 1 # change 1
vm25206.cores = 2 vm25206.cores = 2
vm25206.ram_in_gb = 8 vm25206.ram_in_gb = 8
vm25206.save() vm25206.save()
vm25206.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,4,17))) vm25206.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,4,17)))
Bill.create_next_bill_for_user(user) # change 2
sys.exit(0)
vm25206_ssd.size_in_gb = 50 vm25206_ssd.size_in_gb = 50
vm25206_ssd.save() vm25206_ssd.save()
vm25206_ssd.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,8,5))) vm25206_ssd.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,8,5)))
vm25615 = VMProduct.objects.create(name="OpenNebula 25615", # 25206 done.
cores=1,
ram_in_gb=4, # 25615
owner=user) vm25615 = VMProduct(name="25615", cores=1, ram_in_gb=4, owner=user)
vm25615.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
vm25615.save()
vm25615_ssd = VMDiskProduct(vm=vm25615, owner=user, size_in_gb=30)
vm25615_ssd.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3)))
vm25615_ssd.save()
Bill.create_next_bill_for_user(user)
sys.exit(0)
vm25615_ssd = VMDiskProduct.objects.create(vm=vm25615,
owner=user,
size_in_gb=30)
vm25615.cores = 2 vm25615.cores = 2

View file

@ -685,34 +685,24 @@ oAsAAAAAAACGQNAFAAAAAAAAQyDoAgAAAAAAgCEQdAEAAAAAAMAQCLoAAAAAAABgCP83AL6WQ1Y7
</div> </div>
<div class="d4"> <div class="d4">
<div class="b1"> <div class="b1">
Rechnungsdatum: {{ bill.starting_date|date:"c" }} -
<br> Rechnungsnummer {{ bill.ending_date|date:"c" }}
<br> Zahlbar bis <br>Bill id: {{ bill }}
<br>Due: {{ bill.due_date }}
</div> </div>
<div class="b2">
{{ bill.creation_date.date }}<br>
{% if bill.billing_address.vat_number != "" %}
{{ bill.billing_address.vat_number
}}<br>
{% else %}
None<br>
{% endif %}
{{ bill.billing_address.vat_number }}<br>
{{ bill.due_date }}
</div>
</div> </div>
<div style="clear: both;"></div> <div style="clear: both;"></div>
<div class="d5"> <div class="d5">
<h1>RECHNUNG</h1> <h1>Invoice</h1>
</div> </div>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Detail</th> <th>Detail</th>
<th>Quantity</th> <th>Units</th>
<th>Price/Unit</th> <th>Price/Unit</th>
<th class="tr">Total</tH> <th class="tr">Total price</tH>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -733,17 +723,17 @@ oAsAAAAAAACGQNAFAAAAAAAAQyDoAgAAAAAAgCEQdAEAAAAAAMAQCLoAAAAAAABgCP83AL6WQ1Y7
</table> </table>
<div class="wf th"> <div class="wf th">
<p class="ts"> <p class="ts">
<span class="tl">Total</span> <span class="tl">Total (excl. VAT)</span>
<span class="tr">{{ bill.amount }}</span> <span class="tr">{{ bill.amount }}</span>
</p> </p>
<p class="ts"> <p class="ts">
<span class="tl">VAT</span> <span class="tl">VAT 7.7%</span>
<span class="tr">{{ bill.vat_amount|floatformat:2 }}</span> <span class="tr">{{ bill.vat_amount|floatformat:2 }}</span>
</p> </p>
</div> </div>
<div class="wf pc"> <div class="wf pc">
<p class="bold"> <p class="bold">
<span class="tl">Total</span> <span class="tl">Total amount to be paid</span>
<span class="tr">{{ bill.sum|floatformat:2 }}</span> <span class="tr">{{ bill.sum|floatformat:2 }}</span>
</p> </p>
</div> </div>

View file

@ -144,6 +144,13 @@ class BillAndOrderTestCase(TestCase):
billing_address=BillingAddress.get_address_for(self.recurring_user) billing_address=BillingAddress.get_address_for(self.recurring_user)
) )
# used for generating multiple bills
self.bill_dates = [
timezone.make_aware(datetime.datetime(2020,3,31)),
timezone.make_aware(datetime.datetime(2020,4,30)),
timezone.make_aware(datetime.datetime(2020,5,31)),
]
def test_bill_one_time_one_bill_record(self): def test_bill_one_time_one_bill_record(self):
""" """
@ -173,6 +180,21 @@ class BillAndOrderTestCase(TestCase):
self.assertEqual(self.recurring_order.billrecord_set.count(), 1) self.assertEqual(self.recurring_order.billrecord_set.count(), 1)
self.assertEqual(bill.billrecord_set.count(), 1) self.assertEqual(bill.billrecord_set.count(), 1)
def test_new_bill_after_closing(self):
"""
After closing a bill and the user has a recurring product,
the next bill run should create e new bill
"""
for ending_date in self.bill_dates:
Bill.create_next_bill_for_user(self.recurring_user, ending_date)
bills_count = Bill.objects.filter(owner=self.recurring_user).count()
self.assertEqual(len(self.bill_dates), bill_count)
# class NotABillingTC(TestCase): # class NotABillingTC(TestCase):
# #class BillingTestCase(TestCase): # #class BillingTestCase(TestCase):
# def setUp(self): # def setUp(self):

View file

@ -164,9 +164,7 @@ class VMDiskProduct(Product):
default=VMDiskType.CEPH_SSD) default=VMDiskType.CEPH_SSD)
def __str__(self): def __str__(self):
return "{} disk for VM '{}': {}GB".format(self.disk_type, return f"Disk {self.size_in_gb}GB ({self.disk_type}) for VM '{self.vm.name}'"
self.vm.name,
self.size_in_gb)
@property @property
def recurring_price(self): def recurring_price(self):