diff --git a/hosting/management/commands/fetch_stripe_bills.py b/hosting/management/commands/fetch_stripe_bills.py index 3a06a1d9..6285ec0a 100644 --- a/hosting/management/commands/fetch_stripe_bills.py +++ b/hosting/management/commands/fetch_stripe_bills.py @@ -1,9 +1,13 @@ +import logging + from django.core.management.base import BaseCommand -from hosting.models import UserCardDetail +from hosting.models import MonthlyHostingBill from membership.models import CustomUser from utils.stripe_utils import StripeUtils +logger = logging.getLogger(__name__) + class Command(BaseCommand): help = '''Fetches invoices from Stripe and creates bills for a given @@ -18,11 +22,32 @@ class Command(BaseCommand): stripe_utils = StripeUtils() user = CustomUser.objects.get(email=email) if hasattr(user, 'stripecustomer'): - self.stdout.write(self.style.SUCCESS('Found %s. Fetching bills for him.' % email)) - stripe_utils.get_all_invoices( - user.stripecustomer.stripe_id + self.stdout.write(self.style.SUCCESS( + 'Found %s. Fetching bills for him.' % email)) + mhb = MonthlyHostingBill.objects.last( + customer=user.stripecustomer ) + created_gt = {} + if mhb is not None: + # fetch only invoices which is created after + # mhb.created, because we already have invoices till + # this date + created_gt = {'gt': mhb.created} + + all_invoices_response = stripe_utils.get_all_invoices( + user.stripecustomer.stripe_id, + created=created_gt + ) + all_invoices = all_invoices_response['response_object'] + logger.debug( + "Obtained {} invoices".format(len(all_invoices)) + ) + for invoice in all_invoices: + MonthlyHostingBill.create( + invoice, stripe_customer=user.stripecustomer + ) else: - self.stdout.write(self.style.SUCCESS('Customer email %s does not have a stripe customer.' % email)) + self.stdout.write(self.style.SUCCESS( + 'Customer email %s does not have a stripe customer.' % email)) except Exception as e: print(" *** Error occurred. Details {}".format(str(e))) diff --git a/hosting/models.py b/hosting/models.py index 4e4e2a59..856e83ea 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -235,16 +235,24 @@ class HostingBill(AssignPermissionsMixin, models.Model): class MonthlyHostingBill(AssignPermissionsMixin, models.Model): customer = models.ForeignKey(StripeCustomer) order = models.ForeignKey(HostingOrder) + created = models.DateTimeField(help_text="When the invoice was created") receipt_number = models.CharField( - help_text="The receipt number that is generated on Stripe" + help_text="The receipt number that is generated on Stripe", + max_length=100 ) invoice_number = models.CharField( - help_text="The invoice number that is generated on Stripe" + help_text="The invoice number that is generated on Stripe", + max_length=100 ) - billing_period = models.CharField( - help_text="The billing period for which the bill is valid" - ) - date_paid = models.DateField(help_text="Date on which the bill was paid") + paid_at = models.DateTimeField(help_text="Date on which the bill was paid") + period_start = models.DateTimeField() + period_end = models.DateTimeField() + billing_reason = models.CharField(max_length=25) + discount = models.PositiveIntegerField() + total = models.IntegerField() + lines_data_count = models.IntegerField() + invoice_id = models.CharField(unique=True, max_length=100) + lines_meta_data_csv = models.TextField() permissions = ('view_monthlyhostingbill',) @@ -253,6 +261,24 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model): ('view_monthlyhostingbill', 'View Monthly Hosting'), ) + @classmethod + def create(cls, stripe_customer, **args): + instance = cls.objects.create(args) + instance.customer = stripe_customer + if len(instance.lines_meta_data_csv) > 0: + vm_ids = [vm_id.strip() for vm_id in instance.lines_meta_data_csv.split(",")] + if len(vm_ids) == 1: + instance.order = HostingOrder.objects.get(vm_id=vm_ids[0]) + else: + logger.debug( + "More than one VM_ID" + "for MonthlyHostingBill {}".format(instance.invoice_id) + ) + logger.debug("VM_IDS=".format(','.join(vm_ids))) + instance.assign_permissions(stripe_customer.user) + instance.save() + return instance + class VMDetail(models.Model): user = models.ForeignKey(CustomUser) diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index d412cbd0..63df0133 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -123,23 +123,42 @@ class StripeUtils(object): return card_details @handleStripeError - def get_all_invoices(self, customer_id): - invoices = stripe.Invoice.list(limit=100, customer=customer_id) + def get_all_invoices(self, customer_id, created): return_list = [] - for invoice in invoices: - invoice_details = { - 'created': invoice.created, - 'receipt_number': invoice.receipt_number, - 'invoice_number': invoice.number, - 'date_paid': invoice.date_paid, - 'period_start': invoice.period_start, - 'period_end': invoice.period_end, - 'paid': invoice.paid, - 'billing_reason': invoice.billing_reason, - 'discount': invoice.discount.coupon.amount_off if invoice.discount else 0, - 'total': invoice.total - } - return_list.append(invoice_details) + has_more_invoices = True + starting_after = False + while has_more_invoices: + if starting_after: + invoices = stripe.Invoice.list( + limit=10, customer=customer_id, created=created + ) + else: + invoices = stripe.Invoice.list( + limit=10, customer=customer_id, created=created, + starting_after=starting_after + ) + has_more_invoices = invoices.has_more + for invoice in invoices.data: + invoice_details = { + 'created': invoice.created, + 'receipt_number': invoice.receipt_number, + 'invoice_number': invoice.number, + 'paid_at': invoice.status_transitions.paid_at if invoice.paid else 0, + 'period_start': invoice.period_start, + 'period_end': invoice.period_end, + 'billing_reason': invoice.billing_reason, + 'discount': invoice.discount.coupon.amount_off if invoice.discount else 0, + 'total': invoice.total, + # to see how many line items we have in this invoice and + # then later check if we have more than 1 + 'lines_data_count': len(invoice.lines.data), + 'invoice_id': invoice.id, + 'lines_meta_data_csv': ','.join( + [line.metadata.VM_ID for line in invoice.lines.data] + ) + } + starting_after = invoice.id + return_list.append(invoice_details) return return_list @handleStripeError