From 484bd53bd26c87a1733216b7f875d45f34ba2b84 Mon Sep 17 00:00:00 2001
From: PCoder
Date: Sat, 12 Jan 2019 11:02:33 +0100
Subject: [PATCH 1/5] Fix the way we calculate VAT and final VM price
1. Get the VM's pricing from its config and VMPricing
2. Compute and apply discount if any
3. Apply VAT on the discounted amount from 2
---
.../datacenterlight/order_detail.html | 24 +++++++------
datacenterlight/views.py | 8 ++---
hosting/templates/hosting/order_detail.html | 24 +++++++------
hosting/views.py | 30 ++++------------
utils/hosting_utils.py | 35 ++++++++++++-------
5 files changed, 60 insertions(+), 61 deletions(-)
diff --git a/datacenterlight/templates/datacenterlight/order_detail.html b/datacenterlight/templates/datacenterlight/order_detail.html
index 31933e12..9fd6c9d5 100644
--- a/datacenterlight/templates/datacenterlight/order_detail.html
+++ b/datacenterlight/templates/datacenterlight/order_detail.html
@@ -98,22 +98,26 @@
{% if vm.vat > 0 or vm.discount.amount > 0 %}
- {% if vm.vat > 0 %}
-
- {% trans "Subtotal" %}
- {{vm.price|floatformat:2|intcomma}} CHF
-
-
- {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%)
- {{vm.vat|floatformat:2|intcomma}} CHF
-
- {% endif %}
+
+ {% trans "Subtotal" %}
+ {{vm.price|floatformat:2|intcomma}} CHF
+
{% if vm.discount.amount > 0 %}
{%trans "Discount" as discount_name %}
{{ vm.discount.name|default:discount_name }}
- {{ vm.discount.amount }} CHF
+
+ {% trans "Subtotal after discount" %}
+ {{vm.total_after_discount|floatformat:2|intcomma}} CHF
+
+ {% endif %}
+ {% if vm.vat > 0 %}
+
+ {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%)
+ {{vm.vat|floatformat:2|intcomma}} CHF
+
{% endif %}
diff --git a/datacenterlight/views.py b/datacenterlight/views.py
index 5dc3a3d3..d6441205 100644
--- a/datacenterlight/views.py
+++ b/datacenterlight/views.py
@@ -183,7 +183,7 @@ class IndexView(CreateView):
)
return HttpResponseRedirect(referer_url + "#order_form")
- price, vat, vat_percent, discount = get_vm_price_with_vat(
+ vm_price_dict = get_vm_price_with_vat(
cpu=cores,
memory=memory,
ssd_size=storage,
@@ -193,13 +193,9 @@ class IndexView(CreateView):
'cpu': cores,
'memory': memory,
'disk_size': storage,
- 'price': price,
- 'vat': vat,
- 'vat_percent': vat_percent,
- 'discount': discount,
- 'total_price': round(price + vat - discount['amount'], 2),
'pricing_name': vm_pricing_name
}
+ specs.update(vm_price_dict)
request.session['specs'] = specs
request.session['template'] = template_data
return HttpResponseRedirect(reverse('datacenterlight:payment'))
diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html
index 4a62e9fa..5ba8bc3b 100644
--- a/hosting/templates/hosting/order_detail.html
+++ b/hosting/templates/hosting/order_detail.html
@@ -135,22 +135,26 @@
{% if vm.vat > 0 or vm.discount.amount > 0 %}
- {% if vm.vat > 0 %}
-
- {% trans "Subtotal" %}
- {{vm.price|floatformat:2|intcomma}} CHF
-
-
- {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%)
- {{vm.vat|floatformat:2|intcomma}} CHF
-
- {% endif %}
+
+ {% trans "Subtotal" %}
+ {{vm.price|floatformat:2|intcomma}} CHF
+
{% if vm.discount.amount > 0 %}
{%trans "Discount" as discount_name %}
{{ vm.discount.name|default:discount_name }}
- {{ vm.discount.amount }} CHF
+
+ {% trans "Subtotal after discount" %}
+ {{vm.total_after_discount|floatformat:2|intcomma}} CHF
+
+ {% endif %}
+ {% if vm.vat > 0 %}
+
+ {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%)
+ {{vm.vat|floatformat:2|intcomma}} CHF
+
{% endif %}
diff --git a/hosting/views.py b/hosting/views.py
index 32de4e54..eb6ec1a4 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -878,18 +878,14 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
context['vm'] = vm_detail.__dict__
context['vm']['name'] = '{}-{}'.format(
context['vm']['configuration'], context['vm']['vm_id'])
- price, vat, vat_percent, discount = get_vm_price_with_vat(
+ vm_price_dict = get_vm_price_with_vat(
cpu=context['vm']['cores'],
ssd_size=context['vm']['disk_size'],
memory=context['vm']['memory'],
pricing_name=(obj.vm_pricing.name
if obj.vm_pricing else 'default')
)
- context['vm']['vat'] = vat
- context['vm']['price'] = price
- context['vm']['discount'] = discount
- context['vm']['vat_percent'] = vat_percent
- context['vm']['total_price'] = price + vat - discount['amount']
+ context['vm'] = vm_price_dict
context['subscription_end_date'] = vm_detail.end_date()
except VMDetail.DoesNotExist:
try:
@@ -898,20 +894,14 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
)
vm = manager.get_vm(obj.vm_id)
context['vm'] = VirtualMachineSerializer(vm).data
- price, vat, vat_percent, discount = get_vm_price_with_vat(
+ vm_price_dict = get_vm_price_with_vat(
cpu=context['vm']['cores'],
ssd_size=context['vm']['disk_size'],
memory=context['vm']['memory'],
pricing_name=(obj.vm_pricing.name
if obj.vm_pricing else 'default')
)
- context['vm']['vat'] = vat
- context['vm']['price'] = price
- context['vm']['discount'] = discount
- context['vm']['vat_percent'] = vat_percent
- context['vm']['total_price'] = (
- price + vat - discount['amount']
- )
+ context['vm'] = vm_price_dict
except WrongIdError:
messages.error(
self.request,
@@ -1290,25 +1280,19 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
extra_tags='storage')
return redirect(CreateVirtualMachinesView.as_view())
- price, vat, vat_percent, discount = get_vm_price_with_vat(
+ vm_price_dict = get_vm_price_with_vat(
cpu=cores,
memory=memory,
ssd_size=storage,
pricing_name=vm_pricing_name
)
-
specs = {
'cpu': cores,
'memory': memory,
'disk_size': storage,
- 'discount': discount,
- 'price': price,
- 'vat': vat,
- 'vat_percent': vat_percent,
- 'total_price': round(price + vat - discount['amount'], 2),
- 'pricing_name': vm_pricing_name
+ 'pricing_name': vm_pricing_name,
}
-
+ specs.update(vm_price_dict)
request.session['specs'] = specs
request.session['template'] = template_data
return redirect(reverse('hosting:payment'))
diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py
index ec97a320..b358ebdb 100644
--- a/utils/hosting_utils.py
+++ b/utils/hosting_utils.py
@@ -95,8 +95,14 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
:param ssd_size: Disk space of the VM (SSD)
:param hdd_size: The HDD size
:param pricing_name: The pricing name to be used
- :return: The a tuple containing the price of the VM, the VAT and the
- VAT percentage
+ :return: A dict containing
+ 1. the price of the VM,
+ 2. the applied VAT amount
+ 3. the VAT percentage
+ 4. the discount (a dict containing the discount name and
+ the discount amount),
+ 5. the price after discount
+ 6. the final price
"""
try:
pricing = VMPricing.objects.get(name=pricing_name)
@@ -109,28 +115,33 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
)
return None
- price = (
+ price = decimal.Decimal(
(decimal.Decimal(cpu) * pricing.cores_unit_price) +
(decimal.Decimal(memory) * pricing.ram_unit_price) +
(decimal.Decimal(ssd_size) * pricing.ssd_unit_price) +
(decimal.Decimal(hdd_size) * pricing.hdd_unit_price)
)
+ discount = {
+ 'name': pricing.discount_name,
+ 'amount': round(pricing.discount_amount, 2)
+ }
+ price_after_discount = price - discount['amount']
+
if pricing.vat_inclusive:
vat = decimal.Decimal(0)
vat_percent = decimal.Decimal(0)
else:
- vat = price * pricing.vat_percentage * decimal.Decimal(0.01)
+ vat = price_after_discount * pricing.vat_percentage * decimal.Decimal(0.01)
vat_percent = pricing.vat_percentage
- cents = decimal.Decimal('.01')
- price = price.quantize(cents, decimal.ROUND_HALF_UP)
- vat = vat.quantize(cents, decimal.ROUND_HALF_UP)
- discount = {
- 'name': pricing.discount_name,
- 'amount': round(float(pricing.discount_amount), 2)
+ return {
+ 'price': round(price, 2),
+ 'vat': round(vat, 2),
+ 'vat_percent': round(vat_percent, 2),
+ 'discount': discount,
+ 'price_after_discount': round(price_after_discount, 2),
+ 'total_price': round(price_after_discount + vat, 2)
}
- return (round(float(price), 2), round(float(vat), 2),
- round(float(vat_percent), 2), discount)
def ping_ok(host_ipv6):
From 2186ff1250ea443b478d578ebc83e3f833578ec7 Mon Sep 17 00:00:00 2001
From: PCoder
Date: Sat, 12 Jan 2019 11:40:00 +0100
Subject: [PATCH 2/5] Convert price parameters to float
---
utils/hosting_utils.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py
index b358ebdb..09b8d3d1 100644
--- a/utils/hosting_utils.py
+++ b/utils/hosting_utils.py
@@ -123,7 +123,7 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
)
discount = {
'name': pricing.discount_name,
- 'amount': round(pricing.discount_amount, 2)
+ 'amount': round(float(pricing.discount_amount), 2)
}
price_after_discount = price - discount['amount']
@@ -135,12 +135,12 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
vat_percent = pricing.vat_percentage
return {
- 'price': round(price, 2),
- 'vat': round(vat, 2),
- 'vat_percent': round(vat_percent, 2),
+ 'price': round(float(price), 2),
+ 'vat': round(float(vat), 2),
+ 'vat_percent': round(float(vat_percent), 2),
'discount': discount,
- 'price_after_discount': round(price_after_discount, 2),
- 'total_price': round(price_after_discount + vat, 2)
+ 'price_after_discount': round(float(price_after_discount), 2),
+ 'total_price': round(float(price_after_discount + vat), 2)
}
From 53d5c66bd141b8ce9dd7383cf29669af9cfa4dac Mon Sep 17 00:00:00 2001
From: PCoder
Date: Sat, 12 Jan 2019 11:44:45 +0100
Subject: [PATCH 3/5] Fix bug
Use Decimal discount_amount
---
utils/hosting_utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py
index 09b8d3d1..0d712d4b 100644
--- a/utils/hosting_utils.py
+++ b/utils/hosting_utils.py
@@ -125,7 +125,7 @@ def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
'name': pricing.discount_name,
'amount': round(float(pricing.discount_amount), 2)
}
- price_after_discount = price - discount['amount']
+ price_after_discount = price - pricing.discount_amount
if pricing.vat_inclusive:
vat = decimal.Decimal(0)
From 8bf89e67116b4c0c8581e1773a8795fd39a357ec Mon Sep 17 00:00:00 2001
From: PCoder
Date: Sat, 12 Jan 2019 11:57:02 +0100
Subject: [PATCH 4/5] Use correct variable
total_after_discount -> price_after_discount
---
datacenterlight/templates/datacenterlight/order_detail.html | 2 +-
hosting/templates/hosting/order_detail.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/datacenterlight/templates/datacenterlight/order_detail.html b/datacenterlight/templates/datacenterlight/order_detail.html
index 9fd6c9d5..645722d6 100644
--- a/datacenterlight/templates/datacenterlight/order_detail.html
+++ b/datacenterlight/templates/datacenterlight/order_detail.html
@@ -110,7 +110,7 @@
{% trans "Subtotal after discount" %}
- {{vm.total_after_discount|floatformat:2|intcomma}} CHF
+ {{vm.price_after_discount|floatformat:2|intcomma}} CHF
{% endif %}
{% if vm.vat > 0 %}
diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html
index 5ba8bc3b..e91accb1 100644
--- a/hosting/templates/hosting/order_detail.html
+++ b/hosting/templates/hosting/order_detail.html
@@ -147,7 +147,7 @@
{% trans "Subtotal after discount" %}
- {{vm.total_after_discount|floatformat:2|intcomma}} CHF
+ {{vm.price_after_discount|floatformat:2|intcomma}} CHF
{% endif %}
{% if vm.vat > 0 %}
From e1463127c264d297217a079e94f7649d4e227ab5 Mon Sep 17 00:00:00 2001
From: PCoder
Date: Sat, 12 Jan 2019 12:32:31 +0100
Subject: [PATCH 5/5] Fix bug: use dict update instead of replacing key - 'vm'
---
hosting/views.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hosting/views.py b/hosting/views.py
index eb6ec1a4..615b0774 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -885,7 +885,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
pricing_name=(obj.vm_pricing.name
if obj.vm_pricing else 'default')
)
- context['vm'] = vm_price_dict
+ context['vm'].update(vm_price_dict)
context['subscription_end_date'] = vm_detail.end_date()
except VMDetail.DoesNotExist:
try:
@@ -901,7 +901,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, DetailView):
pricing_name=(obj.vm_pricing.name
if obj.vm_pricing else 'default')
)
- context['vm'] = vm_price_dict
+ context['vm'].update(vm_price_dict)
except WrongIdError:
messages.error(
self.request,