diff --git a/uncloud_pay/admin.py b/uncloud_pay/admin.py index 9c1b809..df2cdde 100644 --- a/uncloud_pay/admin.py +++ b/uncloud_pay/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.template.response import TemplateResponse from django.urls import path +from django.shortcuts import render from django.conf.urls import url 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__)) 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() 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) print(bill) @@ -59,15 +61,29 @@ class BillAdmin(admin.ModelAdmin): return response - # ... - context = dict( - # Include common variables for rendering the admin template. - self.admin_site.each_context(request), - # Anything else you want in the context... -# key=value, - ) + def as_html(self, request, object_id): + bill = self.get_object(request, object_id=object_id) - #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) diff --git a/uncloud_pay/management/commands/add-opennebula-vm-orders.py b/uncloud_pay/management/commands/add-opennebula-vm-orders.py index 658404a..6ca1b63 100644 --- a/uncloud_pay/management/commands/add-opennebula-vm-orders.py +++ b/uncloud_pay/management/commands/add-opennebula-vm-orders.py @@ -50,47 +50,44 @@ class Command(BaseCommand): ) - # 25206 - vm25206 = VMProduct(name="OpenNebula 25206", - cores=1, - ram_in_gb=4, - owner=user) - + # 25206 + SSD + vm25206 = VMProduct(name="25206", cores=1, ram_in_gb=4, owner=user) vm25206.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) vm25206.save() - vm25206_ssd = VMDiskProduct(vm=vm25206, - owner=user, - size_in_gb=30) - + vm25206_ssd = VMDiskProduct(vm=vm25206, owner=user, size_in_gb=30) vm25206_ssd.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) vm25206_ssd.save() - # change 1 vm25206.cores = 2 vm25206.ram_in_gb = 8 vm25206.save() vm25206.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,4,17))) - Bill.create_next_bill_for_user(user) - - - sys.exit(0) - - + # change 2 vm25206_ssd.size_in_gb = 50 vm25206_ssd.save() vm25206_ssd.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,8,5))) - vm25615 = VMProduct.objects.create(name="OpenNebula 25615", - cores=1, - ram_in_gb=4, - owner=user) + # 25206 done. + + # 25615 + 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 diff --git a/uncloud_pay/templates/bill.html.j2 b/uncloud_pay/templates/bill.html.j2 index 10ae1e2..456e4a6 100644 --- a/uncloud_pay/templates/bill.html.j2 +++ b/uncloud_pay/templates/bill.html.j2 @@ -685,34 +685,24 @@ oAsAAAAAAACGQNAFAAAAAAAAQyDoAgAAAAAAgCEQdAEAAAAAAMAQCLoAAAAAAABgCP83AL6WQ1Y7
- Rechnungsdatum: -
Rechnungsnummer -
Zahlbar bis + {{ bill.starting_date|date:"c" }} - + {{ bill.ending_date|date:"c" }} +
Bill id: {{ bill }} +
Due: {{ bill.due_date }}
-
- {{ bill.creation_date.date }}
- {% if bill.billing_address.vat_number != "" %} - {{ bill.billing_address.vat_number - }}
- {% else %} - None
- {% endif %} - {{ bill.billing_address.vat_number }}
- {{ bill.due_date }} -
-

RECHNUNG

+

Invoice

- + - + @@ -733,17 +723,17 @@ oAsAAAAAAACGQNAFAAAAAAAAQyDoAgAAAAAAgCEQdAEAAAAAAMAQCLoAAAAAAABgCP83AL6WQ1Y7
DetailQuantityUnits Price/UnitTotalTotal price

- Total + Total (excl. VAT) {{ bill.amount }}

- VAT + VAT 7.7% {{ bill.vat_amount|floatformat:2 }}

- Total + Total amount to be paid {{ bill.sum|floatformat:2 }}

diff --git a/uncloud_pay/tests.py b/uncloud_pay/tests.py index 2c1182b..9a26e2b 100644 --- a/uncloud_pay/tests.py +++ b/uncloud_pay/tests.py @@ -144,6 +144,13 @@ class BillAndOrderTestCase(TestCase): 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): """ @@ -173,6 +180,21 @@ class BillAndOrderTestCase(TestCase): self.assertEqual(self.recurring_order.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 BillingTestCase(TestCase): # def setUp(self): diff --git a/uncloud_vm/models.py b/uncloud_vm/models.py index 8d9b35f..4033ba0 100644 --- a/uncloud_vm/models.py +++ b/uncloud_vm/models.py @@ -164,9 +164,7 @@ class VMDiskProduct(Product): default=VMDiskType.CEPH_SSD) def __str__(self): - return "{} disk for VM '{}': {}GB".format(self.disk_type, - self.vm.name, - self.size_in_gb) + return f"Disk {self.size_in_gb}GB ({self.disk_type}) for VM '{self.vm.name}'" @property def recurring_price(self):