uncloud/uncloud_v3/app/models.py

175 lines
5.3 KiB
Python

from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.urls import reverse
from django.db.models import Q
class Currency(models.Model):
slug = models.SlugField(null=True, unique=True)
name = models.CharField(max_length=128, unique=True)
short_name = models.CharField(max_length=3, unique=True)
def __str__(self):
return f"{self.name} ({self.short_name})"
class TimeFrame(models.Model):
slug = models.SlugField(null=True, unique=True)
name = models.CharField(max_length=128, unique=True)
seconds = models.IntegerField(null=True, blank=True)
@staticmethod
def secs_to_name(secs):
name = ""
days = 0
hours = 0
if secs >= 24*3600:
days = secs // (24*3600)
secs -= (days*24*3600)
if secs >= 3600:
hours = secs // 3600
secs -= hours*3600
return f"{days} days {hours} hours {secs} seconds"
def __str__(self):
#return "{} ({})".format(self.name, self.secs_to_name(self.seconds))
return f"{self.name}"
class OneTimePrice(models.Model):
value = models.FloatField()
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
class Meta:
ordering = ('value',)
def __str__(self):
return f"{self.value} {self.currency.short_name}"
class PricePerTime(models.Model):
timeframe = models.ForeignKey(TimeFrame, on_delete=models.CASCADE)
value = models.FloatField()
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
def __str__(self):
return f"{self.value}{self.currency.short_name}/{self.timeframe}"
class Resource(models.Model):
slug = models.SlugField(null=True, unique=True) # primary identifier
name = models.CharField(max_length=128, unique=False) # CPU, RAM
unit = models.CharField(max_length=128) # Count, GB
minimum_units = models.FloatField(null=True, blank=True) # might have min
maximum_units = models.FloatField(null=True, blank=True) # might have max
step_size = models.FloatField(default=1) # step size
price_per_time = models.ManyToManyField(PricePerTime, blank=True)
onetime_price = models.ForeignKey(OneTimePrice,
null=True, blank=True,
on_delete=models.CASCADE)
def __str__(self):
if self.minimum_units:
minimum = self.minimum_units
else:
minimum = "No minimum"
if self.maximum_units:
maximum = self.maximum_units
else:
maximum = "No maximum"
pricing = ", ".join([str(x) for x in self.price_per_time.all()])
#return f"{self.slug}: {minimum}-{maximum} (+/-){self.step_size} {self.unit} ({pricing})"
return f"{self.name} ({self.slug})"
class Product(models.Model):
"""
Describes a product a user can buy
"""
slug = models.SlugField(null=True, unique=True)
name = models.CharField(max_length=128, unique=True)
resources = models.ManyToManyField(Resource, blank=True) # List of REQUIRED resources
timeframes = models.ManyToManyField(TimeFrame, blank=True) # List of POSSIBLE timeframes
def has_one_time_price(self):
has_otp = False
for res in self.resources.all():
if res.onetime_price:
has_otp = True
break
return has_otp
def valid_timeframes(self):
"""
Return all timeframes that have all resources configured
"""
valid_tf = []
num_res = self.resources.all().count()
for tf in self.timeframes.all():
# Get all distinct source for this timeframe
res = self.resources.filter(price_per_time__timeframe=tf).distinct().count()
if res == num_res:
valid_tf.append(tf)
return valid_tf
def get_absolute_url(self):
return reverse('product-detail', kwargs={'slug' : self.slug})
def __str__(self):
return self.name
class ResourceOrder(models.Model):
"""
Resources that have been ordered
We need to record the selected value *and* potentially the
calculated price
"""
value = models.FloatField()
resource = models.ForeignKey(Resource, on_delete=models.CASCADE)
def __str__(self):
return f"{self.value} x {self.resource}"
class ProductOrder(models.Model):
"""
Describes a product a user bought
"""
product = models.ForeignKey(Product, on_delete=models.CASCADE)
timeframe = models.ForeignKey(TimeFrame, null=True, blank=True, on_delete=models.CASCADE)
resources = models.ManyToManyField(ResourceOrder)
def __str__(self):
if self.timeframe:
txt = f"Order {self.id}: {self.product} for {self.timeframe}"
else:
txt = f"Order {self.id}: {self.product}"
return txt
class Order(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, editable=False)
creation_date = models.DateTimeField(auto_now_add=True)
starting_date = models.DateTimeField(default=timezone.now)
ending_date = models.DateTimeField(blank=True, null=True)
product = models.ManyToManyField(ProductOrder, blank=True)
#textconfigs = models.ManyToManyField(ResourceConfig)