drinks-manager/app/models.py

151 lines
5.8 KiB
Python
Raw Permalink Normal View History

from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.forms import ValidationError
from django.utils import timezone
# Custom user model
class User(AbstractUser):
balance = models.DecimalField(max_digits=8, decimal_places=2, default=0.00)
allow_order_with_negative_balance = models.BooleanField(default=False)
2022-08-06 18:56:39 +02:00
profile_picture_filename = models.CharField(default="default.svg", max_length=25)
allowed_to_supply = models.BooleanField(default=False)
hide_from_userlist = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
self.balance = 0
self.is_active = False
self.username = f"<deleted user #{self.pk}>"
self.last_name = ""
self.first_name = ""
self.email = ""
super().save()
class Drink(models.Model):
product_name = models.CharField(max_length=64)
content_litres = models.DecimalField(max_digits=6, decimal_places=3, default=0.5)
price = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
available = models.PositiveIntegerField(default=0)
deleted = models.BooleanField(default=False)
# when the following field is true, the amount of drinks will
# not change and will not be displayed.
# available > 0 -> there is a indefinetly amount of drinks left
# available < 1 -> there are no drinks left
do_not_count = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
self.deleted = True
super().save()
def __str__(self):
return f"{self.product_name} ({float(self.content_litres):.2f}l) - {self.price} {settings.CURRENCY_SUFFIX}"
class RegisterTransaction(models.Model):
class Meta:
verbose_name = "transaction"
verbose_name_plural = "transactions"
transaction_sum = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
# the following original_transaction_sum is needed when need to be
# updated, but the old value needs to be known (field is hidden)
old_transaction_sum = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
datetime = models.DateTimeField(default=timezone.now)
is_user_deposit = models.BooleanField(default=False)
is_transfer = models.BooleanField(default=False)
comment = models.TextField(default=" ")
user = models.ForeignKey(User, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
if self._state.adding:
if self.is_user_deposit or self.is_transfer: # update user balance
self.user.balance += self.transaction_sum
self.user.save()
self.old_transaction_sum = self.transaction_sum
super().save(*args, **kwargs)
else:
# update user balance
if self.is_user_deposit or self.is_transfer:
self.user.balance += self.transaction_sum - self.old_transaction_sum
self.user.save()
# update register transaction
self.old_transaction_sum = self.transaction_sum
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
# update user deposit
if self.is_user_deposit or self.is_transfer:
self.user.balance -= self.transaction_sum
self.user.save()
super().delete(*args, kwargs)
def __str__(self): return f"{self.transaction_sum} {settings.CURRENCY_SUFFIX} by {self.user}"
class Order(models.Model):
drink = models.ForeignKey(
"Drink",
on_delete=models.SET_NULL,
null=True,
limit_choices_to=models.Q(available__gt=0) # Query only those drinks with a availability greater than (gt) 0
)
user = models.ForeignKey(User, on_delete=models.CASCADE)
datetime = models.DateTimeField(default=timezone.now)
amount = models.PositiveIntegerField(default=1, editable=False)
# the following fields will be set automatically
# won't use foreign key, because the values of the foreign objects may change over time.
product_name = models.CharField(max_length=64, editable=False)
price_sum = models.DecimalField(max_digits=6, decimal_places=2, default=0, editable=False)
content_litres = models.DecimalField(max_digits=6, decimal_places=3, default=0, editable=False)
# TODO: Add more comments on how and why the save & delete functions are implemented
# address this in a refactoring issue.
def save(self, *args, **kwargs):
drink = Drink.objects.get(pk=self.drink.pk)
if self._state.adding and drink.available > 0:
if not drink.do_not_count:
drink.available -= self.amount
drink.save()
self.product_name = drink.product_name
self.price_sum = drink.price * self.amount
self.content_litres = drink.content_litres
self.user.balance -= self.price_sum
self.user.save()
super().save(*args, **kwargs)
else:
raise ValidationError("This entry can't be changed.")
def delete(self, *args, **kwargs):
self.user.balance += self.price_sum
self.user.save()
drink = Drink.objects.get(pk=self.drink.pk)
if not drink.do_not_count:
drink.available += self.amount
drink.save()
super().delete(*args, **kwargs)
def __str__(self): return f"{self.drink.product_name} ({float(self.drink.content_litres):.2f}l) x {self.amount} - {self.price_sum} {settings.CURRENCY_SUFFIX}"
class Global(models.Model):
# this contains global values that are generated/calculated by code
# e.g. the current balance of the register, ...
name = models.CharField(max_length=42, unique=True, primary_key=True)
comment = models.TextField()
value_float = models.FloatField(default=0.00)
value_string = models.TextField()
def __str__(self): return self.name