Merge remote-tracking branch 'mainRepo/master' into feature/6561/invoices-webhook

This commit is contained in:
PCoder 2019-06-12 06:25:47 +02:00
commit 4147b8f891
40 changed files with 1094 additions and 142 deletions

View file

@ -10,7 +10,7 @@ from django.db import models
from django.utils import timezone
from django.utils.functional import cached_property
from datacenterlight.models import VMPricing, VMTemplate
from datacenterlight.models import VMPricing, VMTemplate, StripePlan
from membership.models import StripeCustomer, CustomUser
from utils.mixins import AssignPermissionsMixin
from utils.models import BillingAddress
@ -212,6 +212,15 @@ class UserHostingKey(models.Model):
# self.save(update_fields=['public_key'])
return private_key, public_key
def delete(self,*args,**kwargs):
if bool(self.private_key) and os.path.isfile(self.private_key.path):
logger.debug("Removing private key {}".format(self.private_key.path))
os.remove(self.private_key.path)
else:
logger.debug("No private_key to remove")
super(UserHostingKey, self).delete(*args,**kwargs)
class HostingBill(AssignPermissionsMixin, models.Model):
customer = models.ForeignKey(StripeCustomer)
@ -276,14 +285,17 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
# Try to infer the HostingOrder from subscription id or VM_ID
if len(args['subscription_ids_csv']) > 0:
sub_ids = [sub_id.strip() for sub_id in args['subscription_ids_csv'].split(",")]
if len(sub_ids) == 1:
set_sub_ids = set(sub_ids)
if len(set_sub_ids) == 1:
# the multiple line items belong to the same subscription
sub_id = set_sub_ids.pop()
try:
args['order'] = HostingOrder.objects.get(
subscription_id=sub_ids[0]
subscription_id=sub_id
)
except HostingOrder.DoesNotExist as dne:
logger.error("Hosting order for {} doesn't exist".format(
sub_ids[0]
sub_id
))
args['order'] = None
else:
@ -293,7 +305,7 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
)
logger.debug("SUB_IDS={}".format(','.join(sub_ids)))
logger.debug("Not importing invoices")
return
return None
elif len(args['lines_meta_data_csv']) > 0:
vm_ids = [vm_id.strip() for vm_id in args['lines_meta_data_csv'].split(",")]
if len(vm_ids) == 1:
@ -305,11 +317,11 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
)
logger.debug("VM_IDS={}".format(','.join(vm_ids)))
logger.debug("Not importing invoices")
return
return None
else:
logger.debug("Neither subscription id nor vm_id available")
logger.debug("Can't import invoice")
return
return None
instance = cls.objects.create(
created=datetime.utcfromtimestamp(
@ -342,6 +354,27 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
if 'line_items' in args:
line_items = args['line_items']
for item in line_items:
stripe_plan = None
if item.type == "subscription" or item.type == "invoiceitem":
# Check stripe plan and prepare it for linking to bill item
stripe_plan_id = item.plan.id
try:
stripe_plan = StripePlan.objects.get(
stripe_plan_id=stripe_plan_id
)
except StripePlan.DoesNotExist as dne:
logger.error(
"StripePlan %s doesn't exist" % stripe_plan_id
)
if stripe_plan_id is not None:
# Create Stripe Plan because we don't have it
stripe_plan = StripePlan.objects.create(
stripe_plan_id=stripe_plan_id,
stripe_plan_name=item.plan.name,
amount=item.plan.amount,
interval=item.plan.interval
)
logger.debug("Creatd StripePlan " + stripe_plan_id)
line_item_instance = HostingBillLineItem.objects.create(
monthly_hosting_bill=instance,
amount=item.amount,
@ -358,7 +391,8 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
# https://stripe.com/docs/api/invoiceitems/object#invoiceitem_object-unit_amount
# So, for the time being I set the unit_amount to 0 if not
# found in the line item
unit_amount=item.unit_amount if hasattr(item, "unit_amount") else 0
unit_amount=item.unit_amount if hasattr(item, "unit_amount") else 0,
stripe_plan=stripe_plan
)
line_item_instance.assign_permissions(instance.customer.user)
instance.assign_permissions(instance.customer.user)
@ -390,14 +424,18 @@ class MonthlyHostingBill(AssignPermissionsMixin, models.Model):
if len(self.lines_meta_data_csv) > 0:
vm_ids = [vm_id.strip() for vm_id in
self.lines_meta_data_csv.split(",")]
if len(vm_ids) == 1:
return vm_ids[0]
unique_vm_ids=set(vm_ids)
unique_vm_ids.discard("")
if len(unique_vm_ids) == 1:
vm_id = unique_vm_ids.pop()
logger.debug("Getting invoice for {}".format(vm_id))
return vm_id
else:
logger.debug(
"More than one VM_ID"
"for MonthlyHostingBill {}".format(self.invoice_id)
)
logger.debug("VM_IDS=".format(','.join(vm_ids)))
logger.debug("VM_IDS={}".format(unique_vm_ids))
return return_value
def get_period_start(self):
@ -427,7 +465,10 @@ class HostingBillLineItem(AssignPermissionsMixin, models.Model):
"""
Corresponds to InvoiceItem object of Stripe
"""
monthly_hosting_bill = models.ForeignKey(MonthlyHostingBill)
monthly_hosting_bill = models.ForeignKey(MonthlyHostingBill,
on_delete=models.CASCADE)
stripe_plan = models.ForeignKey(StripePlan, null=True,
on_delete=models.CASCADE)
amount = models.PositiveSmallIntegerField()
description = models.CharField(max_length=255)
discountable = models.BooleanField()
@ -444,6 +485,55 @@ 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 = ""
# metadata is a dict; a dict with nothing has two chars at least {}
if self.metadata is not None and len(self.metadata) > 2:
try:
vm_dict = json.loads(self.metadata)
item_detail = "VM ID: {}<br/>".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
)
if vm_conf is not None:
item_detail += ("<b>Cores</b>: {}<br/><b>RAM</b>: {} GB<br/>"
"<b>SSD</b>: {} GB<br/>").format(
vm_conf['cores'], int(float(vm_conf['ram'])),
vm_conf['ssd']
)
return item_detail
def get_vm_id(self):
"""
If VM_ID is set in the metadata extract and return it as integer
@ -464,7 +554,7 @@ class VMDetail(models.Model):
disk_size = models.FloatField(default=0.0)
cores = models.FloatField(default=0.0)
memory = models.FloatField(default=0.0)
configuration = models.CharField(default='', max_length=25)
configuration = models.CharField(default='', max_length=128)
ipv4 = models.TextField(default='')
ipv6 = models.TextField(default='')
created_at = models.DateTimeField(auto_now_add=True)