2022-01-02 17:29:35 +00:00
|
|
|
from django.db import models
|
2022-01-02 18:34:55 +00:00
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from django.utils import timezone
|
2022-01-14 23:26:35 +00:00
|
|
|
from django.urls import reverse
|
2022-01-15 22:57:55 +00:00
|
|
|
from django.db.models import Q
|
2022-01-02 17:29:35 +00:00
|
|
|
|
2022-01-02 20:01:03 +00:00
|
|
|
class Currency(models.Model):
|
2022-01-15 22:57:55 +00:00
|
|
|
slug = models.SlugField(null=True, unique=True)
|
2022-01-02 20:01:03 +00:00
|
|
|
name = models.CharField(max_length=128, unique=True)
|
|
|
|
short_name = models.CharField(max_length=3, unique=True)
|
|
|
|
|
|
|
|
def __str__(self):
|
2022-01-14 21:23:39 +00:00
|
|
|
return f"{self.name} ({self.short_name})"
|
2022-01-02 20:01:03 +00:00
|
|
|
|
2022-01-02 18:34:55 +00:00
|
|
|
class TimeFrame(models.Model):
|
2022-01-15 22:57:55 +00:00
|
|
|
slug = models.SlugField(null=True, unique=True)
|
2022-01-02 18:34:55 +00:00
|
|
|
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):
|
2022-01-14 21:23:39 +00:00
|
|
|
#return "{} ({})".format(self.name, self.secs_to_name(self.seconds))
|
|
|
|
return f"{self.name}"
|
2022-01-02 18:34:55 +00:00
|
|
|
|
2022-01-30 09:11:22 +00:00
|
|
|
class OneTimePrice(models.Model):
|
|
|
|
value = models.FloatField()
|
|
|
|
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
|
|
|
|
|
2022-01-30 12:00:58 +00:00
|
|
|
class Meta:
|
|
|
|
ordering = ('value',)
|
|
|
|
|
2022-01-30 09:11:22 +00:00
|
|
|
def __str__(self):
|
|
|
|
return f"{self.value} {self.currency.short_name}"
|
|
|
|
|
2022-01-02 20:01:03 +00:00
|
|
|
class PricePerTime(models.Model):
|
|
|
|
timeframe = models.ForeignKey(TimeFrame, on_delete=models.CASCADE)
|
2022-01-30 09:11:22 +00:00
|
|
|
value = models.FloatField()
|
2022-01-02 20:01:03 +00:00
|
|
|
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
|
|
|
|
|
|
|
|
def __str__(self):
|
2022-01-30 09:11:22 +00:00
|
|
|
return f"{self.value}{self.currency.short_name}/{self.timeframe}"
|
2022-01-02 20:01:03 +00:00
|
|
|
|
2022-01-02 18:34:55 +00:00
|
|
|
class Resource(models.Model):
|
2022-01-14 23:26:35 +00:00
|
|
|
slug = models.SlugField(null=True, unique=True) # primary identifier
|
|
|
|
name = models.CharField(max_length=128, unique=False) # CPU, RAM
|
2022-01-14 21:23:39 +00:00
|
|
|
unit = models.CharField(max_length=128) # Count, GB
|
2022-01-02 18:34:55 +00:00
|
|
|
minimum_units = models.FloatField(null=True, blank=True) # might have min
|
|
|
|
maximum_units = models.FloatField(null=True, blank=True) # might have max
|
2022-01-30 09:11:22 +00:00
|
|
|
step_size = models.FloatField(default=1) # step size
|
2022-01-02 18:34:55 +00:00
|
|
|
|
2022-01-02 20:01:03 +00:00
|
|
|
price_per_time = models.ManyToManyField(PricePerTime, blank=True)
|
2022-01-30 12:00:58 +00:00
|
|
|
#onetime_price = models.ManyToManyField(OneTimePrice, blank=True)
|
|
|
|
onetime_price = models.ForeignKey(OneTimePrice, null=True, on_delete=models.CASCADE)
|
2022-01-02 18:34:55 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
2022-01-14 21:23:39 +00:00
|
|
|
if self.minimum_units:
|
|
|
|
minimum = self.minimum_units
|
|
|
|
else:
|
|
|
|
minimum = "No minimum"
|
|
|
|
if self.maximum_units:
|
|
|
|
maximum = self.maximum_units
|
|
|
|
else:
|
|
|
|
maximum = "No maximum"
|
|
|
|
|
2022-01-30 09:11:22 +00:00
|
|
|
pricing = ", ".join([str(x) for x in self.price_per_time.all()])
|
2022-01-14 21:23:39 +00:00
|
|
|
|
2022-01-30 12:00:58 +00:00
|
|
|
#return f"{self.slug}: {minimum}-{maximum} (+/-){self.step_size} {self.unit} ({pricing})"
|
|
|
|
return f"{self.name} ({self.slug})"
|
2022-01-02 20:01:03 +00:00
|
|
|
|
2022-01-02 18:34:55 +00:00
|
|
|
|
|
|
|
class Product(models.Model):
|
|
|
|
"""
|
|
|
|
Describes a product a user can buy
|
|
|
|
"""
|
|
|
|
|
2022-01-14 23:26:35 +00:00
|
|
|
slug = models.SlugField(null=True, unique=True)
|
2022-01-15 22:57:55 +00:00
|
|
|
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
|
|
|
|
|
2022-01-30 12:00:58 +00:00
|
|
|
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
|
|
|
|
|
2022-01-15 22:57:55 +00:00
|
|
|
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()
|
2022-01-02 18:34:55 +00:00
|
|
|
|
2022-01-15 22:57:55 +00:00
|
|
|
if res == num_res:
|
|
|
|
valid_tf.append(tf)
|
2022-01-02 18:34:55 +00:00
|
|
|
|
2022-01-15 22:57:55 +00:00
|
|
|
return valid_tf
|
2022-01-02 18:34:55 +00:00
|
|
|
|
2022-01-14 23:26:35 +00:00
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('product-detail', kwargs={'slug' : self.slug})
|
|
|
|
|
2022-01-02 18:34:55 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2022-01-16 16:13:59 +00:00
|
|
|
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)
|
|
|
|
|
2022-01-30 12:00:58 +00:00
|
|
|
def __str__(self):
|
|
|
|
return f"{self.value} x {self.resource}"
|
|
|
|
|
2022-01-16 16:13:59 +00:00
|
|
|
|
2022-01-02 20:01:03 +00:00
|
|
|
class ProductOrder(models.Model):
|
|
|
|
"""
|
|
|
|
Describes a product a user bought
|
|
|
|
"""
|
|
|
|
product = models.ForeignKey(Product, on_delete=models.CASCADE)
|
2022-01-30 12:00:58 +00:00
|
|
|
timeframe = models.ForeignKey(TimeFrame, null=True, blank=True, on_delete=models.CASCADE)
|
2022-01-02 20:01:03 +00:00
|
|
|
resources = models.ManyToManyField(ResourceOrder)
|
|
|
|
|
2022-01-30 09:11:22 +00:00
|
|
|
def __str__(self):
|
2022-01-30 12:00:58 +00:00
|
|
|
if self.timeframe:
|
|
|
|
txt = f"Order {self.id}: {self.product} for {self.timeframe}"
|
|
|
|
else:
|
|
|
|
txt = f"Order {self.id}: {self.product}"
|
|
|
|
|
|
|
|
return txt
|
2022-01-30 09:11:22 +00:00
|
|
|
|
|
|
|
|
2022-01-02 18:34:55 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2022-01-02 20:01:03 +00:00
|
|
|
product = models.ManyToManyField(ProductOrder, blank=True)
|
|
|
|
|
2022-01-02 18:34:55 +00:00
|
|
|
#textconfigs = models.ManyToManyField(ResourceConfig)
|