3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-05-18 07:21:47 +00:00
coope/gestion/models.py

459 lines
15 KiB
Python
Raw Permalink Normal View History

2018-08-31 12:46:35 +00:00
from django.db import models
from django.contrib.auth.models import User
2018-11-27 08:07:12 +00:00
from simple_history.models import HistoricalRecords
from django.core.validators import MinValueValidator
2018-12-02 15:28:40 +00:00
from preferences.models import PaymentMethod
from django.core.exceptions import ValidationError
2018-11-27 08:07:12 +00:00
2019-05-03 19:09:32 +00:00
class Category(models.Model):
"""
A product category
"""
class Meta:
verbose_name="Catégorie"
name = models.CharField(max_length=100, verbose_name="Nom", unique=True)
order = models.IntegerField(default=0)
"""
The name of the category
"""
def __str__(self):
return self.name
@property
def active_products(self):
"""
Return active producs of this category
"""
return self.product_set.filter(is_active=True)
2019-08-29 10:35:47 +00:00
@property
def active_stock_products(self):
"""
Return active products that use stocks
"""
return self.product_set.filter(is_active=True).filter(use_stocks=True)
2018-10-05 22:03:02 +00:00
2018-08-31 12:46:35 +00:00
class Product(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores a product.
2018-12-02 15:28:40 +00:00
"""
2019-05-06 07:40:40 +00:00
DRAFT_NONE = 0
DRAFT_PINTE = 1
DRAFT_DEMI = 2
DRAFT_GALOPIN = 3
DRAFT_TYPES = (
(DRAFT_NONE, "Pas une bière pression"),
(DRAFT_PINTE, "Pinte"),
(DRAFT_DEMI, "Demi"),
(DRAFT_GALOPIN, "Galopin"),
)
2018-12-02 15:28:40 +00:00
class Meta:
verbose_name = "Produit"
2019-05-06 07:40:40 +00:00
name = models.CharField(max_length=255, verbose_name="Nom", unique=True)
2019-02-28 12:18:41 +00:00
"""
The name of the product.
"""
2018-11-27 08:07:12 +00:00
amount = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="Prix de vente", validators=[MinValueValidator(0)])
2019-02-28 12:18:41 +00:00
"""
The price of the product.
"""
2019-08-27 21:21:15 +00:00
stock = models.IntegerField(default=0, verbose_name="Stock")
2019-02-28 12:18:41 +00:00
"""
2019-08-27 21:21:15 +00:00
Number of product
2019-02-28 12:18:41 +00:00
"""
2019-05-03 19:09:32 +00:00
category = models.ForeignKey('Category', on_delete=models.PROTECT, verbose_name="Catégorie")
2019-02-28 12:18:41 +00:00
"""
The category of the product
"""
2018-10-05 22:03:02 +00:00
needQuantityButton = models.BooleanField(default=False, verbose_name="Bouton quantité")
2019-02-28 12:18:41 +00:00
"""
If True, a javascript quantity button will be displayed
"""
2018-10-05 22:03:02 +00:00
is_active = models.BooleanField(default=True, verbose_name="Actif")
2019-02-28 12:18:41 +00:00
"""
If True, will be displayed on the :func:`gestion.views.manage` view.
"""
2018-11-27 08:07:12 +00:00
volume = models.PositiveIntegerField(default=0)
2019-02-28 12:18:41 +00:00
"""
The volume, if relevant, of the product
"""
2018-11-27 08:07:12 +00:00
deg = models.DecimalField(default=0,max_digits=5, decimal_places=2, verbose_name="Degré", validators=[MinValueValidator(0)])
2019-02-28 12:18:41 +00:00
"""
Degree of alcohol, if relevant
"""
2018-12-05 00:43:21 +00:00
adherentRequired = models.BooleanField(default=True, verbose_name="Adhérent requis")
2019-02-28 12:18:41 +00:00
"""
If True, only adherents will be able to buy this product
"""
2019-01-06 03:39:30 +00:00
showingMultiplier = models.PositiveIntegerField(default=1)
2019-02-28 12:18:41 +00:00
"""
On the graphs on :func:`users.views.profile` view, the number of total consumptions is divised by the showingMultiplier
"""
2019-05-06 07:40:40 +00:00
draft_category = models.IntegerField(choices=DRAFT_TYPES, default=DRAFT_NONE, verbose_name="Type de pression")
2019-08-29 10:35:47 +00:00
use_stocks = models.BooleanField(default=True, verbose_name="Utiliser les stocks ?")
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
2019-06-09 23:26:54 +00:00
if self.draft_category == self.DRAFT_NONE:
return self.name + " (" + str(self.amount) + " €)"
2019-06-09 23:26:54 +00:00
else:
return self.name + " (" + str(self.amount) + " €, " + str(self.deg) + "°)"
2018-08-31 12:46:35 +00:00
2019-01-18 14:38:48 +00:00
def user_ranking(self, pk):
2019-02-28 12:18:41 +00:00
"""
Return the user ranking for the product
"""
2019-01-18 14:38:48 +00:00
user = User.objects.get(pk=pk)
2019-02-25 10:13:42 +00:00
consumptions = Consumption.objects.filter(customer=user).filter(product=self)
if consumptions:
return (user, consumptions[0].quantity)
else:
return (user, 0)
2019-01-18 14:38:48 +00:00
@property
def ranking(self):
2019-02-28 12:18:41 +00:00
"""
Get the first 25 users with :func:`~gestion.models.user_ranking`
"""
2019-01-18 14:38:48 +00:00
users = User.objects.all()
ranking = [self.user_ranking(user.pk) for user in users]
ranking.sort(key=lambda x:x[1], reverse=True)
return ranking[0:25]
2018-08-31 12:46:35 +00:00
def isPinte(id):
product = Product.objects.get(id=id)
2019-05-06 07:40:40 +00:00
if product.draft_category != Product.DRAFT_PINTE:
2018-08-31 12:46:35 +00:00
raise ValidationError(
('%(product)s n\'est pas une pinte'),
params={'product': product},
)
def isDemi(id):
product = Product.objects.get(id=id)
2019-05-06 07:40:40 +00:00
if product.draft_category != Product.DRAFT_DEMI:
2018-08-31 12:46:35 +00:00
raise ValidationError(
('%(product)s n\'est pas un demi'),
params={'product': product},
)
def isGalopin(id):
2018-12-05 00:43:21 +00:00
product = Product.objects.get(id=id)
2019-05-06 07:40:40 +00:00
if product.draft_category != Product.DRAFT_GALOPIN:
2018-08-31 12:46:35 +00:00
raise ValidationError(
('%(product)s n\'est pas un galopin'),
params={'product': product},
)
2018-10-05 22:03:02 +00:00
class Keg(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores a keg.
2018-12-02 15:28:40 +00:00
"""
2018-11-25 12:52:32 +00:00
class Meta:
2018-12-02 15:28:40 +00:00
verbose_name = "Fût"
2018-11-25 12:52:32 +00:00
permissions = (
("open_keg", "Peut percuter les fûts"),
("close_keg", "Peut fermer les fûts")
)
name = models.CharField(max_length=255, unique=True, verbose_name="Nom")
2019-02-28 12:18:41 +00:00
"""
The name of the keg.
"""
2018-10-05 22:03:02 +00:00
stockHold = models.IntegerField(default=0, verbose_name="Stock en soute")
2019-02-28 12:18:41 +00:00
"""
The number of this keg in the hold.
"""
2018-12-05 00:43:21 +00:00
amount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="Prix du fût", validators=[MinValueValidator(0)])
2019-02-28 12:18:41 +00:00
"""
The price of the keg.
"""
2018-10-05 22:03:02 +00:00
capacity = models.IntegerField(default=30, verbose_name="Capacité (L)")
2019-02-28 12:18:41 +00:00
"""
The capacity, in liters, of the keg.
"""
2018-08-31 12:46:35 +00:00
pinte = models.ForeignKey(Product, on_delete=models.PROTECT, related_name="futp", validators=[isPinte])
2019-02-28 12:18:41 +00:00
"""
The related :class:`~gestion.models.Product` for pint.
"""
2018-08-31 12:46:35 +00:00
demi = models.ForeignKey(Product, on_delete=models.PROTECT, related_name="futd", validators=[isDemi])
2019-02-28 12:18:41 +00:00
"""
The related :class:`~gestion.models.Product` for demi.
"""
2018-08-31 12:46:35 +00:00
galopin = models.ForeignKey(Product, on_delete=models.PROTECT, related_name="futg", validators=[isGalopin],null=True, blank=True)
2019-02-28 12:18:41 +00:00
"""
The related :class:`~gestion.models.Product` for galopin.
"""
2018-10-05 22:03:02 +00:00
is_active = models.BooleanField(default=False, verbose_name="Actif")
2019-02-28 12:18:41 +00:00
"""
If True, will be displayed on :func:`~gestion.views.manage` view
"""
2019-09-20 20:01:51 +00:00
deg = models.DecimalField(default=0,max_digits=5, decimal_places=2, verbose_name="Degré", validators=[MinValueValidator(0)])
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
return self.name
2018-10-05 22:03:02 +00:00
class KegHistory(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores a keg history, related to :class:`~gestion.models.Keg`.
2018-12-02 15:28:40 +00:00
"""
class Meta:
verbose_name = "Historique de fût"
2019-02-27 07:59:41 +00:00
keg = models.ForeignKey(Keg, on_delete=models.PROTECT, verbose_name="Fût")
2019-02-28 12:18:41 +00:00
"""
The :class:`~gestion.models.Keg` instance.
"""
2019-02-27 07:59:41 +00:00
openingDate = models.DateTimeField(auto_now_add=True, verbose_name="Date ouverture")
2019-02-28 12:18:41 +00:00
"""
The date when the keg was opened.
"""
2019-02-27 07:59:41 +00:00
quantitySold = models.DecimalField(decimal_places=2, max_digits=5, default=0, verbose_name="Quantité vendue")
2019-02-28 12:18:41 +00:00
"""
The quantity, in liters, sold.
"""
2019-02-27 07:59:41 +00:00
amountSold = models.DecimalField(decimal_places=2, max_digits=5, default=0, verbose_name="Somme vendue")
2019-02-28 12:18:41 +00:00
"""
The quantity, in euros, sold.
"""
2019-02-27 07:59:41 +00:00
closingDate = models.DateTimeField(null=True, blank=True, verbose_name="Date fermeture")
2019-02-28 12:18:41 +00:00
"""
The date when the keg was closed
"""
2019-02-27 07:59:41 +00:00
isCurrentKegHistory = models.BooleanField(default=True, verbose_name="Actuel")
2019-02-28 12:18:41 +00:00
"""
If True, it corresponds to the current Keg history of :class:`~gestion.models.Keg` instance.
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-10-05 22:03:02 +00:00
2018-11-25 12:52:32 +00:00
def __str__(self):
res = "Fût de " + str(self.keg) + " (" + str(self.openingDate) + " - "
if(self.closingDate):
res += str(self.closingDate) + ")"
else:
res += "?)"
return res
2018-08-31 12:46:35 +00:00
class Reload(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores reloads.
2018-12-02 15:28:40 +00:00
"""
class Meta:
verbose_name = "Rechargement"
2018-10-05 22:03:02 +00:00
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="reload_taken", verbose_name="Client")
2019-02-28 12:18:41 +00:00
"""
Client (:class:`django.contrib.auth.models.User`).
"""
2018-12-05 00:43:21 +00:00
amount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="Montant", validators=[MinValueValidator(0)])
2019-02-28 12:18:41 +00:00
"""
Amount of the reload.
"""
2018-10-05 22:03:02 +00:00
PaymentMethod = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT, verbose_name="Moyen de paiement")
2019-02-28 12:18:41 +00:00
"""
:class:`Payment Method <preferences.models.PaymentMethod>` of the reload.
"""
2018-08-31 12:46:35 +00:00
coopeman = models.ForeignKey(User, on_delete=models.PROTECT, related_name="reload_realized")
2019-02-28 12:18:41 +00:00
"""
Coopeman (:class:`django.contrib.auth.models.User`) who collected the reload.
"""
2018-08-31 12:46:35 +00:00
date = models.DateTimeField(auto_now_add=True)
2019-02-28 12:18:41 +00:00
"""
Date of the reload.
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
return "Rechargement effectue par {0} le {1} ({2} euros, coopeman : {3})".format(self.customer, self.date, self.amount, self.coopeman)
class Refund(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores refunds.
2018-12-02 15:28:40 +00:00
"""
class Meta:
verbose_name = "Remboursement"
2018-08-31 12:46:35 +00:00
date = models.DateTimeField(auto_now_add=True)
2019-02-28 12:18:41 +00:00
"""
Date of the refund
"""
2018-10-05 22:03:02 +00:00
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="refund_taken", verbose_name="Client")
2019-02-28 12:18:41 +00:00
"""
Client (:class:`django.contrib.auth.models.User`).
"""
2018-12-05 00:43:21 +00:00
amount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="Montant", validators=[MinValueValidator(0)])
2019-02-28 12:18:41 +00:00
"""
Amount of the refund.
"""
2018-08-31 12:46:35 +00:00
coopeman = models.ForeignKey(User, on_delete=models.PROTECT, related_name="refund_realized")
2019-02-28 12:18:41 +00:00
"""
Coopeman (:class:`django.contrib.auth.models.User`) who realized the refund.
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
return "{0} remboursé de {1} le {2} (effectué par {3})".format(self.customer, self.amount, self.date, self.coopeman)
class Menu(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores menus.
2018-12-02 15:28:40 +00:00
"""
2018-10-05 22:03:02 +00:00
name = models.CharField(max_length=255, verbose_name="Nom")
2019-02-28 12:18:41 +00:00
"""
Name of the menu.
"""
2018-12-05 00:43:21 +00:00
amount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="Montant", validators=[MinValueValidator(0)])
2019-02-28 12:18:41 +00:00
"""
Price of the menu.
"""
2018-10-05 22:03:02 +00:00
articles = models.ManyToManyField(Product, verbose_name="Produits")
2019-02-28 12:18:41 +00:00
"""
Stores :class:`Products <gestion.models.Product>` contained in the menu
"""
2018-10-05 22:03:02 +00:00
is_active = models.BooleanField(default=False, verbose_name="Actif")
2019-02-28 12:18:41 +00:00
"""
If True, the menu will be displayed on the :func:`gestion.views.manage` view
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
return self.name
2018-11-27 08:07:12 +00:00
@property
def adherent_required(self):
2019-02-28 12:18:41 +00:00
"""
Test if the menu contains a restricted :class:`~gestion.models.Product`
"""
2018-11-27 08:07:12 +00:00
res = False
for article in self.articles.all():
res = res or article.adherentRequired
return res
2018-08-31 12:46:35 +00:00
class MenuHistory(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores MenuHistory related to :class:`~gestion.models.Menu`.
2018-12-02 15:28:40 +00:00
"""
class Meta:
verbose_name = "Historique de menu"
2019-02-27 07:59:41 +00:00
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="menu_taken", verbose_name="Client")
2019-02-28 12:18:41 +00:00
2019-02-27 07:59:41 +00:00
quantity = models.PositiveIntegerField(default=0, verbose_name="Quantité")
2019-02-28 12:18:41 +00:00
"""
Client (:class:`django.contrib.auth.models.User`).
"""
2019-02-27 07:59:41 +00:00
paymentMethod = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT, verbose_name="Moyen de paiement")
2019-02-28 12:18:41 +00:00
"""
:class:`Payment Method <preferences.models.PaymentMethod>` of the Menu purchased.
"""
2018-08-31 12:46:35 +00:00
date = models.DateTimeField(auto_now_add=True)
2019-02-28 12:18:41 +00:00
"""
Date of the purhcase.
"""
2018-08-31 12:46:35 +00:00
menu = models.ForeignKey(Menu, on_delete=models.PROTECT)
2019-02-28 12:18:41 +00:00
"""
:class:`gestion.models.Menu` purchased.
"""
2019-02-27 07:59:41 +00:00
amount = models.DecimalField(max_digits=7, decimal_places=2, default=0, verbose_name="Montant")
2019-02-28 12:18:41 +00:00
"""
Price of the purchase.
"""
2018-08-31 12:46:35 +00:00
coopeman = models.ForeignKey(User, on_delete=models.PROTECT, related_name="menu_selled")
2019-02-28 12:18:41 +00:00
"""
Coopeman (:class:django.contrib.auth.models.User`) who collected the money.
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
2018-11-22 21:52:15 +00:00
return "{2} a consommé {0} {1}".format(self.quantity, self.menu, self.customer)
2018-08-31 12:46:35 +00:00
class ConsumptionHistory(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores consumption history related to Product
2018-12-02 15:28:40 +00:00
"""
class Meta:
verbose_name = "Consommation"
2019-02-27 07:59:41 +00:00
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="consumption_taken", verbose_name="Client")
2019-02-28 12:18:41 +00:00
"""
Client (:class:`django.contrib.auth.models.User`).
"""
2019-02-27 07:59:41 +00:00
quantity = models.PositiveIntegerField(default=0, verbose_name="Quantité")
2019-02-28 12:18:41 +00:00
"""
Quantity of :attr:`gestion.models.ConsumptionHistory.product` taken.
"""
2019-02-27 07:59:41 +00:00
paymentMethod = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT, verbose_name="Moyen de paiement")
2019-02-28 12:18:41 +00:00
"""
:class:`Payment Method <preferences.models.PaymentMethod>` of the product purchased.
"""
2018-08-31 12:46:35 +00:00
date = models.DateTimeField(auto_now_add=True)
2019-02-28 12:18:41 +00:00
"""
Date of the purhcase.
"""
2019-02-27 07:59:41 +00:00
product = models.ForeignKey(Product, on_delete=models.PROTECT, verbose_name="Produit")
2019-02-28 12:18:41 +00:00
"""
:class:`gestion.models.product` purchased.
"""
2019-02-27 07:59:41 +00:00
amount = models.DecimalField(max_digits=7, decimal_places=2, default=0, verbose_name="Montant")
2019-02-28 12:18:41 +00:00
"""
Price of the purchase.
"""
2018-08-31 12:46:35 +00:00
coopeman = models.ForeignKey(User, on_delete=models.PROTECT, related_name="consumption_selled")
2019-02-28 12:18:41 +00:00
"""
Coopeman (:class:django.contrib.auth.models.User`) who collected the money.
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-08-31 12:46:35 +00:00
def __str__(self):
return "{0} {1} consommé par {2} le {3} (encaissé par {4})".format(self.quantity, self.product, self.customer, self.date, self.coopeman)
2018-11-25 12:52:32 +00:00
class Consumption(models.Model):
2018-12-02 15:28:40 +00:00
"""
2019-02-28 12:18:41 +00:00
Stores total consumptions.
2018-12-02 15:28:40 +00:00
"""
class Meta:
verbose_name = "Consommation totale"
2019-02-27 07:59:41 +00:00
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="consumption_global_taken", verbose_name="Client")
2019-02-28 12:18:41 +00:00
"""
Client (:class:`django.contrib.auth.models.User`).
"""
2019-02-27 07:59:41 +00:00
product = models.ForeignKey(Product, on_delete=models.PROTECT, verbose_name="Produit")
2019-02-28 12:18:41 +00:00
"""
A :class:`gestion.models.Product` instance.
"""
2019-02-27 07:59:41 +00:00
quantity = models.PositiveIntegerField(default=0, verbose_name="Quantité")
2019-02-28 12:18:41 +00:00
"""
The total number of :attr:`gestion.models.Consumption.product` consumed by the :attr:`gestion.models.Consumption.consumer`.
"""
2018-11-27 08:07:12 +00:00
history = HistoricalRecords()
2018-11-25 12:52:32 +00:00
def __str__(self):
return "Consommation de " + str(self.customer) + " concernant le produit " + str(self.product)
2018-12-21 20:35:09 +00:00
class Pinte(models.Model):
"""
Stores a physical pinte
"""
current_owner = models.ForeignKey(User, on_delete=models.PROTECT, null=True, default=None, related_name="pintes_owned_currently")
2019-02-28 12:18:41 +00:00
"""
The current owner (:class:`django.contrib.auth.models.User`).
"""
previous_owner = models.ForeignKey(User, on_delete=models.PROTECT, null=True, default=None, related_name="pintes_owned_previously")
2019-02-28 12:18:41 +00:00
"""
The previous owner (:class:`django.contrib.auth.models.User`).
"""
2018-12-21 20:35:09 +00:00
last_update_date = models.DateTimeField(auto_now=True)
2019-02-28 12:18:41 +00:00
"""
The last update date
"""
history = HistoricalRecords()