From a00a9f6ff054f0e6f31070cdf9b5ff54e4f342e1 Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 20 Jan 2020 12:07:32 +0530 Subject: [PATCH] Show invoices directly from stripe --- datacenterlight/templatetags/custom_tags.py | 62 ++++++++++++++- hosting/templates/hosting/dashboard.html | 2 +- hosting/templates/hosting/invoices.html | 60 ++++++++------- hosting/views.py | 83 ++++++++------------- utils/hosting_utils.py | 9 +++ 5 files changed, 139 insertions(+), 77 deletions(-) diff --git a/datacenterlight/templatetags/custom_tags.py b/datacenterlight/templatetags/custom_tags.py index a2b20bcb..4cc50caa 100644 --- a/datacenterlight/templatetags/custom_tags.py +++ b/datacenterlight/templatetags/custom_tags.py @@ -1,6 +1,11 @@ +import datetime + from django import template from django.core.urlresolvers import resolve, reverse -from django.utils.translation import activate, get_language +from django.utils.safestring import mark_safe +from django.utils.translation import activate, get_language, ugettext_lazy as _ + +from utils.hosting_utils import get_ip_addresses register = template.Library() @@ -52,3 +57,58 @@ def escaped_line_break(value): :return: """ return value.replace("\\n", "\n") + + +@register.filter('get_line_item_from_stripe_invoice') +def get_line_item_from_stripe_invoice(invoice): + """ + Returns ready-to-use "html" line item to be shown for an invoice in the + invoice list page + + :param invoice: the stripe Invoice object + :return: + """ + start_date = 0 + end_date = 0 + is_first = True + vm_id = -1 + for line_data in invoice["lines"]["data"]: + if is_first: + start_date = line_data.period.start + end_date = line_data.period.end + is_first = False + if hasattr(line_data.metadata, "VM_ID"): + vm_id = line_data.metadata.VM_ID + else: + if line_data.period.start < start_date: + start_date = line_data.period.start + if line_data.period.end > end_date: + end_date = line_data.period.end + if hasattr(line_data.metadata, "VM_ID"): + vm_id = line_data.metadata.VM_ID + + try: + vm_id = int(vm_id) + except ValueError as ve: + print(str(ve)) + if invoice["lines"]["data"]: + return mark_safe(""" + {vm_id} + {ip_addresses} + {period} + {total} + + {see_invoice_text} + + """.format( + vm_id=vm_id if vm_id > 0 else "", + ip_addresses=mark_safe(get_ip_addresses(vm_id)) if vm_id > 0 else "", + period = mark_safe("%s — %s" % ( + datetime.datetime.fromtimestamp(start_date).strftime('%Y-%m-%d'), + datetime.datetime.fromtimestamp(end_date).strftime('%Y-%m-%d'))), + total=invoice.total/100, + stripe_invoice_url=invoice.hosted_invoice_url, + see_invoice_text=_("See Invoice") + )) + else: + return "" diff --git a/hosting/templates/hosting/dashboard.html b/hosting/templates/hosting/dashboard.html index bda6eb11..212c5885 100644 --- a/hosting/templates/hosting/dashboard.html +++ b/hosting/templates/hosting/dashboard.html @@ -29,7 +29,7 @@ - +

{% trans "My Bills" %}

diff --git a/hosting/templates/hosting/invoices.html b/hosting/templates/hosting/invoices.html index 5f7be4b4..f48802d1 100644 --- a/hosting/templates/hosting/invoices.html +++ b/hosting/templates/hosting/invoices.html @@ -26,36 +26,46 @@ - {% for invoice in invoices %} + {% for inv_data in invs %} - {{ invoice.order.vm_id }} - {{ ips|get_value_from_dict:invoice.invoice_number|join:"
" }} - {% with period|get_value_from_dict:invoice.invoice_number as period_to_show %} - {{ period_to_show.period_start | date:'Y-m-d' }} — {{ period_to_show.period_end | date:'Y-m-d' }} - {% endwith %} - {{ invoice.total_in_chf|floatformat:2|intcomma }} - -
{% trans 'See Invoice' %} - + {{ inv_data | get_line_item_from_stripe_invoice }} {% endfor %} - - {% if is_paginated %} - +{% if invs.has_other_pages %} + +{% endif %} +
{% endblock %} diff --git a/hosting/views.py b/hosting/views.py index bd72af94..c5d505bf 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -3,6 +3,7 @@ import uuid from datetime import datetime from time import sleep +import stripe from django import forms from django.conf import settings from django.contrib import messages @@ -10,6 +11,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ValidationError from django.core.files.base import ContentFile +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.urlresolvers import reverse_lazy, reverse from django.http import ( Http404, HttpResponseRedirect, HttpResponse, JsonResponse @@ -40,7 +42,6 @@ from datacenterlight.models import VMTemplate, VMPricing from datacenterlight.utils import ( create_vm, get_cms_integration, check_otp, validate_vat_number ) -from dynamicweb.settings.base import DCL_ERROR_EMAILS_TO_LIST from hosting.models import UserCardDetail from membership.models import CustomUser, StripeCustomer from opennebula_api.models import OpenNebulaManager @@ -57,11 +58,10 @@ from utils.hosting_utils import ( get_vm_price_with_vat, get_vm_price_for_given_vat, HostingUtils, get_vat_rate_for_country ) +from utils.ldap_manager import LdapManager from utils.mailer import BaseEmail from utils.stripe_utils import StripeUtils from utils.tasks import send_plain_email_task -from utils.ldap_manager import LdapManager - from utils.views import ( PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin, ResendActivationLinkViewMixin @@ -73,7 +73,7 @@ from .forms import ( from .mixins import ProcessVMSelectionMixin, HostingContextMixin from .models import ( HostingOrder, HostingBill, HostingPlan, UserHostingKey, VMDetail, - GenericProduct, MonthlyHostingBill, HostingBillLineItem + GenericProduct, MonthlyHostingBill ) logger = logging.getLogger(__name__) @@ -1240,7 +1240,7 @@ class OrdersHostingListView(LoginRequiredMixin, ListView): return super(OrdersHostingListView, self).get(request, *args, **kwargs) -class InvoiceListView(LoginRequiredMixin, ListView): +class InvoiceListView(LoginRequiredMixin, TemplateView): template_name = "hosting/invoices.html" login_url = reverse_lazy('hosting:login') context_object_name = "invoices" @@ -1248,10 +1248,13 @@ class InvoiceListView(LoginRequiredMixin, ListView): ordering = '-created' def get_context_data(self, **kwargs): + page = self.request.GET.get('page', 1) context = super(InvoiceListView, self).get_context_data(**kwargs) + invs_page = None if ('user_email' in self.request.GET and self.request.user.email == settings.ADMIN_EMAIL): user_email = self.request.GET['user_email'] + context['user_email'] = user_email logger.debug( "user_email = {}".format(user_email) ) @@ -1260,54 +1263,34 @@ class InvoiceListView(LoginRequiredMixin, ListView): except CustomUser.DoesNotExist as dne: logger.debug("User does not exist") cu = self.request.user - mhbs = MonthlyHostingBill.objects.filter(customer__user=cu) - else: - mhbs = MonthlyHostingBill.objects.filter( - customer__user=self.request.user - ) - ips_dict = {} - line_item_period_dict = {} - for mhb in mhbs: + invs = stripe.Invoice.list(customer=cu.stripecustomer.stripe_id, + count=100) + paginator = Paginator(invs.data, 10) try: - vm_detail = VMDetail.objects.get(vm_id=mhb.order.vm_id) - ips_dict[mhb.invoice_number] = [vm_detail.ipv6, vm_detail.ipv4] - all_line_items = HostingBillLineItem.objects.filter(monthly_hosting_bill=mhb) - for line_item in all_line_items: - if line_item.get_item_detail_str() != "": - line_item_period_dict[mhb.invoice_number] = { - "period_start": line_item.period_start, - "period_end": line_item.period_end - } - break - except VMDetail.DoesNotExist as dne: - ips_dict[mhb.invoice_number] = ['--'] - logger.debug("VMDetail for {} doesn't exist".format( - mhb.order.vm_id - )) - context['ips'] = ips_dict - context['period'] = line_item_period_dict + invs_page = paginator.page(page) + except PageNotAnInteger: + invs_page = paginator.page(1) + except EmptyPage: + invs_page = paginator.page(paginator.num_pages) + else: + try: + invs = stripe.Invoice.list( + customer=self.request.user.stripecustomer.stripe_id, + count=100 + ) + paginator = Paginator(invs.data, 10) + try: + invs_page = paginator.page(page) + except PageNotAnInteger: + invs_page = paginator.page(1) + except EmptyPage: + invs_page = paginator.page(paginator.num_pages) + except Exception as ex: + logger.error(str(ex)) + invs_page = None + context["invs"] = invs_page return context - def get_queryset(self): - user = self.request.user - if ('user_email' in self.request.GET - and self.request.user.email == settings.ADMIN_EMAIL): - user_email = self.request.GET['user_email'] - logger.debug( - "user_email = {}".format(user_email) - ) - try: - cu = CustomUser.objects.get(email=user_email) - except CustomUser.DoesNotExist as dne: - logger.debug("User does not exist") - cu = self.request.user - self.queryset = MonthlyHostingBill.objects.filter(customer__user=cu) - else: - self.queryset = MonthlyHostingBill.objects.filter( - customer__user=self.request.user - ) - return super(InvoiceListView, self).get_queryset() - @method_decorator(decorators) def get(self, request, *args, **kwargs): return super(InvoiceListView, self).get(request, *args, **kwargs) diff --git a/utils/hosting_utils.py b/utils/hosting_utils.py index 73e2c035..3674185c 100644 --- a/utils/hosting_utils.py +++ b/utils/hosting_utils.py @@ -199,6 +199,15 @@ def get_vat_rate_for_country(country): return 0 +def get_ip_addresses(vm_id): + try: + vm_detail = VMDetail.objects.get(vm_id=vm_id) + return "%s
%s" % (vm_detail.ipv6, vm_detail.ipv4) + except VMDetail.DoesNotExist as dne: + logger.error(str(dne)) + logger.error("VMDetail for %s does not exist" % vm_id) + return "--" + class HostingUtils: @staticmethod def clear_items_from_list(from_list, items_list):