diff --git a/hosting/models.py b/hosting/models.py
index d4a51763..19e73cca 100644
--- a/hosting/models.py
+++ b/hosting/models.py
@@ -473,6 +473,51 @@ class HostingBillLineItem(AssignPermissionsMixin, models.Model):
('view_hostingbilllineitem', 'View Monthly Hosting Bill Line Item'),
)
+ def amount_in_chf(self):
+ """
+ Returns amount in chf. The amount in this model is in cents (as in
+ Stripe). Hence we multiply it by 0.01 to obtain the result
+
+ :return:
+ """
+ return self.amount * 0.01
+
+ def unit_amount_in_chf(self):
+ """
+ Returns unit amount in chf. If its 0, we obtain it from amount and
+ quantity.
+
+ :return:
+ """
+ if self.unit_amount == 0:
+ return round((self.amount / self.quantity) * 0.01, 2)
+ else:
+ return self.unit_amount * 0.01
+
+ def get_item_detail_str(self):
+ """
+ Returns line item html string representation
+ :return:
+ """
+ item_detail = ""
+ if self.metadata is not None and len(self.metadata) > 0:
+ try:
+ vm_dict = json.loads(self.metadata)
+ item_detail = "VM ID: {}
".format(vm_dict["VM_ID"])
+ except ValueError as ve:
+ logger.error(
+ "Could not parse VM in metadata {}. Detail {}".format(
+ self.metadata, str(ve)
+ )
+ )
+ vm_conf = StripeUtils.get_vm_config_from_stripe_id(
+ self.stripe_plan.stripe_plan_id
+ )
+ item_detail += ("Cores: {}
RAM: {} GB
"
+ "SSD: {} GB
").format(
+ vm_conf['cores'], int(float(vm_conf['ram'])), vm_conf['ssd']
+ )
+ return item_detail
class VMDetail(models.Model):
user = models.ForeignKey(CustomUser)
diff --git a/hosting/static/hosting/css/order.css b/hosting/static/hosting/css/order.css
index 8aafb8a8..e68ade33 100644
--- a/hosting/static/hosting/css/order.css
+++ b/hosting/static/hosting/css/order.css
@@ -112,4 +112,17 @@
.dcl-place-order-text {
color: #808080;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+tr.border_bottom td {
+ border-bottom:1pt solid #eee;
+}
+
+tr.grand-total-padding td {
+ padding-top: 10px;
+ font-weight: bold;
}
\ No newline at end of file
diff --git a/hosting/templates/hosting/invoice_detail.html b/hosting/templates/hosting/invoice_detail.html
index e63f25a7..d1411db0 100644
--- a/hosting/templates/hosting/invoice_detail.html
+++ b/hosting/templates/hosting/invoice_detail.html
@@ -89,80 +89,91 @@
- {% trans "Product" %}: - {% if vm.name %} - {{ vm.name }} - {% endif %} -
-Product | Period | Qty | Unit Price | Total |
---|---|---|---|---|
{% if line_item.description|length > 0 %}{{line_item.description}}{% else %}{{line_item.get_item_detail_str|safe}}{% endif %} | {{ line_item.period_start | date:'Y-m-d' }} — {{ line_item.period_end | date:'Y-m-d' }} | {{line_item.quantity}} | {{line_item.unit_amount_in_chf}} | {{line_item.amount_in_chf}} |
Grand Total | {{total_in_chf}} |
- {% trans "Period" %}: - - {{ period_start|date:'Y-m-d h:i a' }} - {{ period_end|date:'Y-m-d h:i a' }} - -
- {% endif %} -- {% trans "Cores" %}: - {% if vm.cores %} - {{vm.cores|floatformat}} - {% else %} - {{vm.cpu|floatformat}} + {% trans "Product" %}: + {% if vm.name %} + {{ vm.name }} {% endif %}
-- {% trans "Memory" %}: - {{vm.memory}} GB -
-- {% trans "Disk space" %}: - {{vm.disk_size}} GB -
-- {% trans "Subtotal" %} - {{vm.price|floatformat:2|intcomma}} - CHF -
-- {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) - - {{vm.vat|floatformat:2|intcomma}} CHF -
- {% endif %} - {% if vm.discount.amount > 0 %} -- {%trans "Discount" as discount_name %} - {{ vm.discount.name|default:discount_name }} - - {{ vm.discount.amount }} CHF -
++ {% trans "Period" %}: + + {{ period_start|date:'Y-m-d h:i a' }} - {{ period_end|date:'Y-m-d h:i a' }} + +
+ {% endif %} ++ {% trans "Cores" %}: + {% if vm.cores %} + {{vm.cores|floatformat}} + {% else %} + {{vm.cpu|floatformat}} + {% endif %} +
++ {% trans "Memory" %}: + {{vm.memory}} GB +
++ {% trans "Disk space" %}: + {{vm.disk_size}} GB +
++ {% trans "Subtotal" %} + {{vm.price|floatformat:2|intcomma}} + CHF +
++ {% trans "VAT" %} ({{ vm.vat_percent|floatformat:2|intcomma }}%) + + {{vm.vat|floatformat:2|intcomma}} CHF +
+ {% endif %} + {% if vm.discount.amount > 0 %} ++ {%trans "Discount" as discount_name %} + {{ vm.discount.name|default:discount_name }} + - {{ vm.discount.amount }} CHF +
+ {% endif %} ++ {% trans "Total" %} + {% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} + CHF +
+- {% trans "Total" %} - {% if vm.total_price %}{{vm.total_price|floatformat:2|intcomma}}{% else %}{{vm.price|floatformat:2|intcomma}}{% endif %} - CHF -
-{% trans "Product" %}: diff --git a/hosting/views.py b/hosting/views.py index fe13ff21..2d7a3093 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1284,8 +1284,8 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView): # fallback to get it from the infrastructure try: manager = OpenNebulaManager( - email=self.request.email, - password=self.request.password + email=self.request.user.email, + password=self.request.user.password ) vm = manager.get_vm(vm_id) context['vm'] = VirtualMachineSerializer(vm).data @@ -1322,6 +1322,9 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView): context['total_in_chf'] = obj.total_in_chf() context['invoice_number'] = obj.invoice_number context['discount_on_stripe'] = obj.discount_in_chf() + if obj.lines_data_count > 1: + # special case, we pass the details of each of the line items + context['line_items'] = obj.hostingbilllineitem_set.all() return context else: raise Http404 diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index a3682514..4334d6cf 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -1,4 +1,5 @@ import logging +import re import stripe from django.conf import settings from datacenterlight.models import StripePlan @@ -376,6 +377,32 @@ class StripeUtils(object): else: return stripe_plan_id_string + @staticmethod + def get_vm_config_from_stripe_id(stripe_id): + """ + Given a string like "dcl-v1-cpu-2-ram-5gb-ssd-10gb" return different + configuration params as a dict + + :param stripe_id|str + :return: dict + """ + pattern = re.compile(r'^dcl-v(\d+)-cpu-(\d+)-ram-(\d+\.?\d*)gb-ssd-(\d+)gb-?(\d*\.?\d*)(chf)?$') + match_res = pattern.match(stripe_id) + if match_res is not None: + price = None + try: + price=match_res.group(5) + except IndexError as ie: + logger.debug("Did not find price in {}".format(stripe_id)) + return { + 'version': match_res.group(1), + 'cores': match_res.group(2), + 'ram': match_res.group(3), + 'ssd': match_res.group(4), + 'price': price + } + + @staticmethod def get_stripe_plan_name(cpu, memory, disk_size, price): """