diff --git a/coopeV3/settings.py b/coopeV3/settings.py
index 62250b1..30f5d45 100644
--- a/coopeV3/settings.py
+++ b/coopeV3/settings.py
@@ -56,6 +56,7 @@ MIDDLEWARE = [
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',
+ 'django.contrib.admindocs.middleware.XViewMiddleware',
]
ROOT_URLCONF = 'coopeV3.urls'
diff --git a/gestion/migrations/0009_auto_20181202_1628.py b/gestion/migrations/0009_auto_20181202_1628.py
new file mode 100644
index 0000000..f4ef280
--- /dev/null
+++ b/gestion/migrations/0009_auto_20181202_1628.py
@@ -0,0 +1,87 @@
+# Generated by Django 2.1 on 2018-12-02 15:28
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('gestion', '0008_auto_20181130_1904'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='historicalstocking',
+ name='history_user',
+ ),
+ migrations.DeleteModel(
+ name='Stocking',
+ ),
+ migrations.AlterModelOptions(
+ name='consumption',
+ options={'verbose_name': 'Consommation totale'},
+ ),
+ migrations.AlterModelOptions(
+ name='consumptionhistory',
+ options={'verbose_name': 'Consommation'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalconsumption',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Consommation totale'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalconsumptionhistory',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Consommation'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalkeg',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Fût'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalkeghistory',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Historique de fût'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalmenuhistory',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Historique de menu'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalproduct',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Produit'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalrefund',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Remboursement'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalreload',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Rechargement'},
+ ),
+ migrations.AlterModelOptions(
+ name='keg',
+ options={'permissions': (('open_keg', 'Peut percuter les fûts'), ('close_keg', 'Peut fermer les fûts')), 'verbose_name': 'Fût'},
+ ),
+ migrations.AlterModelOptions(
+ name='keghistory',
+ options={'verbose_name': 'Historique de fût'},
+ ),
+ migrations.AlterModelOptions(
+ name='menuhistory',
+ options={'verbose_name': 'Historique de menu'},
+ ),
+ migrations.AlterModelOptions(
+ name='product',
+ options={'verbose_name': 'Produit'},
+ ),
+ migrations.AlterModelOptions(
+ name='refund',
+ options={'verbose_name': 'Remboursement'},
+ ),
+ migrations.AlterModelOptions(
+ name='reload',
+ options={'verbose_name': 'Rechargement'},
+ ),
+ migrations.DeleteModel(
+ name='HistoricalStocking',
+ ),
+ ]
diff --git a/gestion/models.py b/gestion/models.py
index a553bde..b83ddef 100644
--- a/gestion/models.py
+++ b/gestion/models.py
@@ -1,12 +1,15 @@
from django.db import models
from django.contrib.auth.models import User
-from preferences.models import PaymentMethod
-from django.core.exceptions import ValidationError
from simple_history.models import HistoricalRecords
from django.core.validators import MinValueValidator
+from preferences.models import PaymentMethod
+from django.core.exceptions import ValidationError
class Product(models.Model):
+ """
+ Stores a product
+ """
P_PRESSION = 'PP'
D_PRESSION = 'DP'
G_PRESSION = 'GP'
@@ -23,6 +26,8 @@ class Product(models.Model):
(FOOD, "Bouffe autre que panini"),
(PANINI, "Bouffe pour panini"),
)
+ class Meta:
+ verbose_name = "Produit"
name = models.CharField(max_length=40, verbose_name="Nom", unique=True)
amount = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="Prix de vente", validators=[MinValueValidator(0)])
stockHold = models.IntegerField(default=0, verbose_name="Stock en soute")
@@ -66,7 +71,11 @@ def isGalopin(id):
)
class Keg(models.Model):
+ """
+ Stores a keg
+ """
class Meta:
+ verbose_name = "Fût"
permissions = (
("open_keg", "Peut percuter les fûts"),
("close_keg", "Peut fermer les fûts")
@@ -87,6 +96,12 @@ class Keg(models.Model):
return self.name
class KegHistory(models.Model):
+ """
+ Stores a keg history, related to :model:`gestion.Keg`
+ """
+ class Meta:
+ verbose_name = "Historique de fût"
+
keg = models.ForeignKey(Keg, on_delete=models.PROTECT)
openingDate = models.DateTimeField(auto_now_add=True)
quantitySold = models.DecimalField(decimal_places=2, max_digits=5, default=0)
@@ -104,6 +119,12 @@ class KegHistory(models.Model):
return res
class Reload(models.Model):
+ """
+ Stores reloads
+ """
+ class Meta:
+ verbose_name = "Rechargement"
+
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="reload_taken", verbose_name="Client")
amount = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="Montant", validators=[MinValueValidator(0)])
PaymentMethod = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT, verbose_name="Moyen de paiement")
@@ -124,15 +145,13 @@ class Raming(models.Model):
def __str__(self):
return "Percussion d'un {0} effectué par {1} le {2}".format(self.keg, self.coopeman, self.date)
-class Stocking(models.Model):
- date = models.DateTimeField(auto_now_add=True)
- history = HistoricalRecords()
-
- def __str__(self):
- return "Inventaire fait le {0}".format(self.date)
-
-
class Refund(models.Model):
+ """
+ Stores refunds
+ """
+ class Meta:
+ verbose_name = "Remboursement"
+
date = models.DateTimeField(auto_now_add=True)
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="refund_taken", verbose_name="Client")
amount = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="Montant", validators=[MinValueValidator(0)])
@@ -144,6 +163,9 @@ class Refund(models.Model):
class Menu(models.Model):
+ """
+ Stores menus
+ """
name = models.CharField(max_length=255, verbose_name="Nom")
amount = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="Montant", validators=[MinValueValidator(0)])
barcode = models.CharField(max_length=20, unique=True, verbose_name="Code barre")
@@ -162,6 +184,12 @@ class Menu(models.Model):
return res
class MenuHistory(models.Model):
+ """
+ Stores MenuHistory related to :model:`gestion.Menu`
+ """
+ class Meta:
+ verbose_name = "Historique de menu"
+
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="menu_taken")
quantity = models.PositiveIntegerField(default=0)
paymentMethod = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT)
@@ -175,6 +203,12 @@ class MenuHistory(models.Model):
return "{2} a consommé {0} {1}".format(self.quantity, self.menu, self.customer)
class ConsumptionHistory(models.Model):
+ """
+ Stores consumption history related to :model:`gestion.Product`
+ """
+ class Meta:
+ verbose_name = "Consommation"
+
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="consumption_taken")
quantity = models.PositiveIntegerField(default=0)
paymentMethod = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT)
@@ -188,6 +222,12 @@ class ConsumptionHistory(models.Model):
return "{0} {1} consommé par {2} le {3} (encaissé par {4})".format(self.quantity, self.product, self.customer, self.date, self.coopeman)
class Consumption(models.Model):
+ """
+ Stores total consumptions
+ """
+ class Meta:
+ verbose_name = "Consommation totale"
+
customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="consumption_global_taken")
product = models.ForeignKey(Product, on_delete=models.PROTECT)
quantity = models.PositiveIntegerField(default=0)
diff --git a/gestion/templates/gestion/annual_ranking.html b/gestion/templates/gestion/annual_ranking.html
deleted file mode 100644
index e3ea586..0000000
--- a/gestion/templates/gestion/annual_ranking.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{% extends "base.html" %}
-{%load static %}
-{%block entete%}
Classement
{%endblock%}
-{% block nav %}
-
-{% endblock %}
-{% block content %}
-
-
-
-
-
-
- Dû à des problèmes techniques, cet onglet n'est actuellement pas disponible.
-
-
-
-
-
-{%endblock%}
\ No newline at end of file
diff --git a/gestion/templates/gestion/manage.html b/gestion/templates/gestion/manage.html
index 3b107d6..b329d2a 100644
--- a/gestion/templates/gestion/manage.html
+++ b/gestion/templates/gestion/manage.html
@@ -39,6 +39,7 @@
diff --git a/gestion/urls.py b/gestion/urls.py
index e4828cd..c05a330 100644
--- a/gestion/urls.py
+++ b/gestion/urls.py
@@ -29,7 +29,6 @@ urlpatterns = [
path('getProduct/', views.getProduct, name="getProduct"),
path('order', views.order, name="order"),
path('ranking', views.ranking, name="ranking"),
- path('annualRanking', views.annualRanking, name="annualRanking"),
path('searchProduct', views.searchProduct, name="searchProduct"),
path('cancelConsumption/', views.cancel_consumption, name="cancelConsumption"),
path('cancelMenu/', views.cancel_menu, name="cancelMenu"),
diff --git a/gestion/views.py b/gestion/views.py
index 0964297..4f0826d 100644
--- a/gestion/views.py
+++ b/gestion/views.py
@@ -21,6 +21,45 @@ from preferences.models import PaymentMethod
@login_required
@acl_or('gestion.add_consumptionhistory', 'gestion.add_reload', 'gestion.add_refund')
def manage(request):
+ """
+ Display the manage page
+
+ **Context**
+
+ ``gestion_form``
+ The manage form
+
+ ``reload_form``
+ The :model:`gestion.Reload` form
+
+ ``refund_form``
+ The :model:`gestion.Refund` form
+
+ ``bieresPression``
+ A list of active :model:`gestion.Product` corresponding to draft beers
+
+ ``bieresBouteille``
+ A list of active :model:`gestion.Product` corresponding to bottle beers
+
+ ``panini``
+ A list of active :model:`gestion.Product` corresponding to panini items
+
+ ``food``
+ A list of active :model:`gestion.Product` corresponding to non-panini items
+
+ ``soft``
+ A list of active :model:`gestion.Product` correspond to non alcoholic beverage
+
+ ``menus``
+ The list of active :model:`gestion.Menu`
+
+ ``pay_buttons``
+ List of :model:`paymentMethod`
+
+ **Template**
+
+ :template:`gestion/manage.html`
+ """
pay_buttons = PaymentMethod.objects.filter(is_active=True)
gestion_form = GestionForm(request.POST or None)
reload_form = ReloadForm(request.POST or None)
@@ -39,12 +78,27 @@ def manage(request):
bieresPression.append(keg.demi)
if(keg.galopin):
bieresPression.append(keg.galopin)
- return render(request, "gestion/manage.html", {"gestion_form": gestion_form, "reload_form": reload_form, "refund_form": refund_form, "bieresPression": bieresPression, "bieresBouteille": bieresBouteille, "panini": panini, "food": food, "soft": soft, "menus": menus, "pay_buttons": pay_buttons})
+ return render(request, "gestion/manage.html", {
+ "gestion_form": gestion_form,
+ "reload_form": reload_form,
+ "refund_form": refund_form,
+ "bieresPression": bieresPression,
+ "bieresBouteille": bieresBouteille,
+ "panini": panini,
+ "food": food,
+ "soft": soft,
+ "menus": menus,
+ "pay_buttons": pay_buttons
+ })
+@active_required
@login_required
@permission_required('gestion.add_consumptionhistory')
@csrf_exempt
def order(request):
+ """
+ Process the given order. Called by a js/JQuery script.
+ """
if("user" not in request.POST or "paymentMethod" not in request.POST or "amount" not in request.POST or "order" not in request.POST):
return HttpResponse("Erreur du POST")
else:
@@ -120,34 +174,42 @@ def order(request):
article.save()
return HttpResponse("La commande a bien été effectuée")
+@active_required
@login_required
@permission_required('gestion.add_reload')
def reload(request):
+ """
+ Process a reload request
+ """
reload_form = ReloadForm(request.POST or None)
- if(reload_form.is_valid()):
- reloadEntry = reload_form.save(commit=False)
- reloadEntry.coopeman = request.user
- reloadEntry.save()
+ if reload_form.is_valid():
+ reload_entry = reload_form.save(commit=False)
+ reload_entry.coopeman = request.user
+ reload_entry.save()
user = reload_form.cleaned_data['customer']
amount = reload_form.cleaned_data['amount']
user.profile.credit += amount
user.save()
- messages.success(request,"Le compte de " + user.username + " a bien été crédité de " + str(amount) + "€")
+ messages.success(request, "Le compte de " + user.username + " a bien été crédité de " + str(amount) + "€")
else:
messages.error(request, "Le rechargement a échoué")
return redirect(reverse('gestion:manage'))
+@active_required
@login_required
@permission_required('gestion.add_refund')
def refund(request):
+ """
+ Process a refund request
+ """
refund_form = RefundForm(request.POST or None)
- if(refund_form.is_valid()):
+ if refund_form.is_valid():
user = refund_form.cleaned_data['customer']
amount = refund_form.cleaned_data['amount']
- if(amount <= user.profile.balance):
- refundEntry = refund_form.save(commit = False)
- refundEntry.coopeman = request.user
- refundEntry.save()
+ if amount <= user.profile.balance:
+ refund_entry = refund_form.save(commit = False)
+ refund_entry.coopeman = request.user
+ refund_entry.save()
user.profile.credit -= amount
user.save()
messages.success(request, "Le compte de " + user.username + " a bien été remboursé de " + str(amount) + "€")
@@ -157,9 +219,16 @@ def refund(request):
messages.error(request, "Le remboursement a échoué")
return redirect(reverse('gestion:manage'))
+@active_required
@login_required
@permission_required('gestion.delete_consumptionhistory')
def cancel_consumption(request, pk):
+ """
+ Cancel a :model:`gestion.ConsumptionHistory`
+
+ ``pk``
+ The primary key of the :model:`gestion.ConsumptionHistory` that have to be cancelled
+ """
consumption = get_object_or_404(ConsumptionHistory, pk=pk)
user = consumption.customer
user.profile.debit -= consumption.amount
@@ -168,9 +237,16 @@ def cancel_consumption(request, pk):
messages.success(request, "La consommation a bien été annulée")
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
+@active_required
@login_required
@permission_required('gestion.delete_menuhistory')
def cancel_menu(request, pk):
+ """
+ Cancel a :model:`gestion.MenuHistory`
+
+ ``pk``
+ The primary key of the :model:`gestion.MenuHistory` that have to be cancelled
+ """
menu_history = get_object_or_404(MenuHistory, pk=pk)
user = menu_history.customer
user.profile.debit -= menu_history.amount
@@ -180,15 +256,41 @@ def cancel_menu(request, pk):
return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
########## Products ##########
-
+@active_required
@login_required
@acl_or('gestion.add_product', 'gestion.view_product', 'gestion.add_keg', 'gestion.view_keg', 'gestion.change_keg', 'gestion.view_menu', 'gestion.add_menu')
def productsIndex(request):
+ """
+ Display the products manage static page
+
+ **Template**
+
+ :template:`gestion/products_index.html`
+ """
return render(request, "gestion/products_index.html")
+@active_required
@login_required
@permission_required('gestion.add_product')
def addProduct(request):
+ """
+ Form to add a :model:`gestion.Product`
+
+ **Context**
+
+ ``form``
+ The ProductForm instance
+
+ ``form_title``
+ The title for the form template
+
+ ``form_button``
+ The text of the button for the form template
+
+ **Template**
+
+ :template:`form.html`
+ """
form = ProductForm(request.POST or None)
if(form.is_valid()):
form.save()
@@ -196,9 +298,31 @@ def addProduct(request):
return redirect(reverse('gestion:productsList'))
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter"})
+@active_required
@login_required
-@permission_required('gestion.edit_product')
+@permission_required('gestion.change_product')
def editProduct(request, pk):
+ """
+ Form to edit a :model:`gestion.Product`
+
+ ``pk``
+ The primary key of the requested :model:`gestion.Product`
+
+ **Context**
+
+ ``form``
+ The ProductForm instance
+
+ ``form_title``
+ The title for the form template
+
+ ``form_button``
+ The text of the button for the form template
+
+ **Template**
+
+ :template:`form.html`
+ """
product = get_object_or_404(Product, pk=pk)
form = ProductForm(request.POST or None, instance=product)
if(form.is_valid()):
@@ -207,38 +331,96 @@ def editProduct(request, pk):
return redirect(reverse('gestion:productsList'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un produit", "form_button": "Modifier"})
+@active_required
@login_required
@permission_required('gestion.view_product')
def productsList(request):
+ """
+ Display the list of :model:`gestion.Product`
+
+ **Context**
+
+ ``products``
+ The list of :model:`gestion.Product`
+
+ **Template**
+
+ :template:`gestion/products_list.html`
+ """
products = Product.objects.all()
return render(request, "gestion/products_list.html", {"products": products})
+@active_required
@login_required
@permission_required('gestion.view_product')
def searchProduct(request):
+ """
+ Form to search a :model:`gestion.Product`
+
+ **Context**
+
+ ``form``
+ The SearchProductForm instance
+
+ ``form_title``
+ The title for the form template
+
+ ``form_button``
+ The text of the button for the form template
+
+ **Template**
+
+ :template:`form.html`
+ """
form = SearchProductForm(request.POST or None)
if(form.is_valid()):
return redirect(reverse('gestion:productProfile', kwargs={'pk': form.cleaned_data['product'].pk }))
return render(request, "form.html", {"form": form, "form_title":"Rechercher un produit", "form_button": "Rechercher"})
+@active_required
@login_required
@permission_required('gestion.view_product')
def productProfile(request, pk):
+ """
+ Display the profile of a :model:`gestion.Product`
+
+ ``pk``
+ The primary key of the requested :model:`gestion.Product`
+
+ **Context**
+
+ ``product``
+ The :model:`gestion.Product` instance
+
+ **Template**
+
+ :model:`gestion/product_profile.html`
+ """
product = get_object_or_404(Product, pk=pk)
return render(request, "gestion/product_profile.html", {"product": product})
-
+
+@active_required
@login_required
def getProduct(request, barcode):
+ """
+ Get :model:`gestion.Product` by barcode. Called by a js/JQuery script
+
+ ``barcode``
+ The requested barcode
+ """
product = Product.objects.get(barcode=barcode)
data = json.dumps({"pk": product.pk, "barcode" : product.barcode, "name": product.name, "amount" : product.amount})
return HttpResponse(data, content_type='application/json')
+@active_required
@login_required
-@permission_required('gestion.edit_product')
+@permission_required('gestion.change_product')
def switch_activate(request, pk):
"""
- If the product is active, switch to not active.
- If the product is not active, switch to active.
+ Switch the active status of the requested :model:`gestion.Product`
+
+ ``pk``
+ The primary key of the :model:`gestion.Product`
"""
product = get_object_or_404(Product, pk=pk)
product.is_active = 1 - product.is_active
@@ -247,6 +429,9 @@ def switch_activate(request, pk):
return redirect(reverse('gestion:productsList'))
class ProductsAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete view for all :model:`gestion.Product`
+ """
def get_queryset(self):
qs = Product.objects.all()
if self.q:
@@ -255,9 +440,28 @@ class ProductsAutocomplete(autocomplete.Select2QuerySetView):
########## Kegs ##########
+@active_required
@login_required
@permission_required('gestion.add_keg')
def addKeg(request):
+ """
+ Display a form to add a :model:`gestion.Keg`
+
+ **Context**
+
+ ``form``
+ The KegForm instance
+
+ ``form_title``
+ The title for the :template:`form.html` template
+
+ ``form_button``
+ The text for the button in :template:`form.html` template
+
+ **Template**
+
+ :template:`form.html`
+ """
form = KegForm(request.POST or None)
if(form.is_valid()):
keg = form.save()
@@ -265,9 +469,31 @@ def addKeg(request):
return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un fût", "form_button": "Ajouter"})
+@active_required
@login_required
-@permission_required('gestion.edit_keg')
+@permission_required('gestion.change_keg')
def editKeg(request, pk):
+ """
+ Display a form to edit a :model:`gestion.Keg`
+
+ ``pk``
+ The primary key of the requested :model:`gestion.Keg`
+
+ **Context**
+
+ ``form``
+ The KegForm instance
+
+ ``form_title``
+ The title for the :template:`form.html` template
+
+ ``form_button``
+ The text for the button in :template:`form.html` template
+
+ **Template**
+
+ :template:`form.html`
+ """
keg = get_object_or_404(Keg, pk=pk)
form = KegForm(request.POST or None, instance=keg)
if(form.is_valid()):
@@ -276,9 +502,28 @@ def editKeg(request, pk):
return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un fût", "form_button": "Modifier"})
+@active_required
@login_required
@permission_required('gestion.open_keg')
def openKeg(request):
+ """
+ Display a form to open a :model:`gestion.Keg`
+
+ **Context**
+
+ ``form``
+ The SelectPositiveKegForm instance
+
+ ``form_title``
+ The title for the :template:`form.html` template
+
+ ``form_button``
+ The text for the button in :template:`form.html` template
+
+ **Template**
+
+ :template:`form.html`
+ """
form = SelectPositiveKegForm(request.POST or None)
if(form.is_valid()):
keg = form.cleaned_data['keg']
@@ -296,9 +541,16 @@ def openKeg(request):
return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form": form, "form_title":"Percutage d'un fût", "form_button":"Percuter"})
+@active_required
@login_required
@permission_required('gestion.open_keg')
def openDirectKeg(request, pk):
+ """
+ Open the requested :model:`gestion.Keg`
+
+ ``pk``
+ The primary key of the :model:`gestion.Keg`
+ """
keg = get_object_or_404(Keg, pk=pk)
if(keg.stockHold > 0):
previousKegHistory = KegHistory.objects.filter(keg=keg).filter(isCurrentKegHistory=True)
@@ -316,9 +568,28 @@ def openDirectKeg(request, pk):
messages.error(request, "Il n'y a pas de fût en stock")
return redirect(reverse('gestion:kegsList'))
+@active_required
@login_required
@permission_required('gestion.close_keg')
def closeKeg(request):
+ """
+ Display a form to close a :model:`gestion.Keg`
+
+ **Context**
+
+ ``form``
+ The SelectActiveKegForm instance
+
+ ``form_title``
+ The title for the :template:`form.html` template
+
+ ``form_button``
+ The text for the button in :template:`form.html` template
+
+ **Template**
+
+ :template:`form.html`
+ """
form = SelectActiveKegForm(request.POST or None)
if(form.is_valid()):
keg = form.cleaned_data['keg']
@@ -332,11 +603,18 @@ def closeKeg(request):
return redirect(reverse('gestion:kegsList'))
return render(request, "form.html", {"form": form, "form_title":"Fermeture d'un fût", "form_button":"Fermer le fût"})
+@active_required
@login_required
-@permission_required('gestion:close_keg')
+@permission_required('gestion.close_keg')
def closeDirectKeg(request, pk):
+ """
+ Close the requested :model:`gestion.Keg`
+
+ ``pk``
+ The pk of the active :model:`gestion.Keg`
+ """
keg = get_object_or_404(Keg, pk=pk)
- if(keg.is_active):
+ if keg.is_active:
kegHistory = get_object_or_404(KegHistory, keg=keg, isCurrentKegHistory=True)
kegHistory.isCurrentKegHistory = False
kegHistory.closingDate = timezone.now()
@@ -348,22 +626,60 @@ def closeDirectKeg(request, pk):
messages.error(request, "Le fût n'est pas ouvert")
return redirect(reverse('gestion:kegsList'))
+@active_required
@login_required
@permission_required('gestion.view_keg')
def kegsList(request):
+ """
+ Display the list of :model:`gestion.Keg`
+
+ **Context**
+
+ ``kegs_active``
+ List of active :model:`gestion.Keg`
+
+ ``kegs_inactive``
+ List of inactive :model:`gestion.Keg`
+
+ **Template**
+
+ :template:`gestion/kegs_list.html`
+ """
kegs_active = KegHistory.objects.filter(isCurrentKegHistory=True)
ids_actives = kegs_active.values('id')
kegs_inactive = Keg.objects.exclude(id__in = ids_actives)
return render(request, "gestion/kegs_list.html", {"kegs_active": kegs_active, "kegs_inactive": kegs_inactive})
+@active_required
@login_required
@permission_required('gestion.view_keghistory')
def kegH(request, pk):
+ """
+ Display the history of requested :model:`gestion.Keg`
+
+ ``pk``
+ The primary key of the requested :model:`gestion.Keg`
+
+ **Context**
+
+ ``keg``
+ The :model:`gestion.Keg` instance
+
+ ``kegHistory``
+ List of :model:`gestion.KegHistory` attached to keg
+
+ **Template**
+
+ :template:`gestion/kegh.html`
+ """
keg = get_object_or_404(Keg, pk=pk)
kegHistory = KegHistory.objects.filter(keg=keg).order_by('-openingDate')
return render(request, "gestion/kegh.html", {"keg": keg, "kegHistory": kegHistory})
class KegActiveAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete view for active :model:`gestion.Keg`
+ """
def get_queryset(self):
qs = Keg.objects.filter(is_active = True)
if self.q:
@@ -371,6 +687,9 @@ class KegActiveAutocomplete(autocomplete.Select2QuerySetView):
return qs
class KegPositiveAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete view for :model:`gestion.Keg` with positive stockHold
+ """
def get_queryset(self):
qs = Keg.objects.filter(stockHold__gt = 0)
if self.q:
@@ -379,9 +698,28 @@ class KegPositiveAutocomplete(autocomplete.Select2QuerySetView):
########## Menus ##########
+@active_required
@login_required
@permission_required('gestion.add_menu')
def addMenu(request):
+ """
+ Display a form to add a :model:`gestion.Menu`
+
+ **Context**
+
+ ``form``
+ The MenuForm instance
+
+ ``form_title``
+ The title for the :template:`form.html` template
+
+ ``form_button``
+ The text for the button in :template:`form.html` template
+
+ **Template**
+
+ :template:`form.html`
+ """
form = MenuForm(request.POST or None)
extra_css = "#id_articles{height:200px;}"
if(form.is_valid()):
@@ -390,9 +728,31 @@ def addMenu(request):
return redirect(reverse('gestion:menusList'))
return render(request, "form.html", {"form":form, "form_title": "Ajout d'un menu", "form_button": "Ajouter", "extra_css": extra_css})
+@active_required
@login_required
-@permission_required('gestion.edit_menu')
+@permission_required('gestion.change_menu')
def edit_menu(request, pk):
+ """
+ Display a form to edit a :model:`gestion.Menu`
+
+ ``pk``
+ The primary key of requested :model:`gestion.Menu`
+
+ **Context**
+
+ ``form``
+ The MenuForm instance
+
+ ``form_title``
+ The title for the :template:`form.html` template
+
+ ``form_button``
+ The text for the button in :template:`form.html` template
+
+ **Template**
+
+ :template:`form.html`
+ """
menu = get_object_or_404(Menu, pk=pk)
form = MenuForm(request.POST or None, instance=menu)
extra_css = "#id_articles{height:200px;}"
@@ -402,11 +762,12 @@ def edit_menu(request, pk):
return redirect(reverse('gestion:menusList'))
return render(request, "form.html", {"form": form, "form_title": "Modification d'un menu", "form_button": "Modifier", "extra_css": extra_css})
+@active_required
@login_required
@permission_required('gestion.view_menu')
def searchMenu(request):
"""
- Search a menu via SearchMenuForm instance
+ Search a :model:`gestion.Menu` via SearchMenuForm instance
**Context**
@@ -429,18 +790,34 @@ def searchMenu(request):
return redirect(reverse('gestion:editMenu', kwargs={'pk':menu.pk}))
return render(request, "form.html", {"form": form, "form_title": "Recherche d'un menu", "form_button": "Modifier"})
+@active_required
@login_required
@permission_required('gestion.view_menu')
def menus_list(request):
+ """
+ Display the :model:`gestion.Menu` list
+
+ **Context**
+
+ ``menus``
+ The list of :model:`gestion.Menu` instances
+
+ **Template**
+
+ :template:`gestion/menus_list.html`
+ """
menus = Menu.objects.all()
return render(request, "gestion/menus_list.html", {"menus": menus})
+@active_required
@login_required
-@permission_required('gestion.edit_menu')
+@permission_required('gestion.change_menu')
def switch_activate_menu(request, pk):
"""
- If the menu is active, switch to not active.
- If the menu is not active, switch to active.
+ Switch active status of a :model:`gestion.Menu`
+
+ ``pk``
+ The pk of the :model:`gestion.Menu`
"""
menu = get_object_or_404(Menu, pk=pk)
menu.is_active = 1 - menu.is_active
@@ -448,22 +825,50 @@ def switch_activate_menu(request, pk):
messages.success(request, "La disponibilité du menu a bien été changée")
return redirect(reverse('gestion:menusList'))
+@active_required
@login_required
+@permission_required('gestion.view_menu')
def get_menu(request, barcode):
+ """
+ Search :model:`gestion.Menu` by barcode
+
+ ``barcode``
+ The requested barcode
+ """
menu = get_object_or_404(Menu, barcode=barcode)
data = json.dumps({"pk": menu.pk, "barcode" : menu.barcode, "name": menu.name, "amount" : menu.amount})
return HttpResponse(data, content_type='application/json')
class MenusAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Used as autcomplete for all :model:`gestion.Menu`
+ """
def get_queryset(self):
qs = Menu.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
+
########## Ranking ##########
+@active_required
@login_required
def ranking(request):
+ """
+ Display the ranking page
+
+ **Context**
+
+ ``bestBuyers``
+ List of the 25 best buyers
+
+ ``bestDrinkers``
+ List of the 25 best drinkers
+
+ **Template**
+
+ :template: `gestion/ranking.html`
+ """
bestBuyers = User.objects.order_by('-profile__debit')[:25]
customers = User.objects.all()
list = []
@@ -471,8 +876,4 @@ def ranking(request):
alcohol = customer.profile.alcohol
list.append([customer, alcohol])
bestDrinkers = sorted(list, key=lambda x: x[1], reverse=True)[:25]
- return render(request, "gestion/ranking.html", {"bestBuyers": bestBuyers, "bestDrinkers": bestDrinkers})
-
-@login_required
-def annualRanking(request):
- return render(request, "gestion/annual_ranking.html")
+ return render(request, "gestion/ranking.html", {"bestBuyers": bestBuyers, "bestDrinkers": bestDrinkers})
\ No newline at end of file
diff --git a/preferences/forms.py b/preferences/forms.py
index bfcb2f0..d6224c6 100644
--- a/preferences/forms.py
+++ b/preferences/forms.py
@@ -4,17 +4,26 @@ from django.core.exceptions import ValidationError
from .models import Cotisation, PaymentMethod, GeneralPreferences
class CotisationForm(forms.ModelForm):
+ """
+ Form to add and edit cotisations
+ """
class Meta:
model = Cotisation
fields = "__all__"
class PaymentMethodForm(forms.ModelForm):
+ """
+ Form to add and edit payment methods
+ """
class Meta:
model = PaymentMethod
fields = "__all__"
class GeneralPreferencesForm(forms.ModelForm):
+ """
+ Form to edit the general preferences
+ """
class Meta:
model = GeneralPreferences
fields = "__all__"
diff --git a/preferences/models.py b/preferences/models.py
index 13781b1..8f41f74 100644
--- a/preferences/models.py
+++ b/preferences/models.py
@@ -4,6 +4,9 @@ from django.core.validators import MinValueValidator
class PaymentMethod(models.Model):
+ """
+ Stores payment methods
+ """
name = models.CharField(max_length=255, verbose_name="Nom")
is_active = models.BooleanField(default=True, verbose_name="Actif")
is_usable_in_cotisation = models.BooleanField(default=True, verbose_name="Cotisations ?")
@@ -15,6 +18,9 @@ class PaymentMethod(models.Model):
return self.name
class GeneralPreferences(models.Model):
+ """
+ Stores a unique line of general preferences
+ """
is_active = models.BooleanField(default=True)
active_message = models.TextField(blank=True)
global_message = models.TextField(blank=True)
@@ -27,6 +33,9 @@ class GeneralPreferences(models.Model):
history = HistoricalRecords()
class Cotisation(models.Model):
+ """
+ Stores cotisations
+ """
amount = models.DecimalField(max_digits=5, decimal_places=2, null=True, verbose_name="Montant", validators=[MinValueValidator(0)])
duration = models.PositiveIntegerField(verbose_name="Durée de la cotisation (jours)")
history = HistoricalRecords()
diff --git a/preferences/views.py b/preferences/views.py
index 58ff90b..a832db2 100644
--- a/preferences/views.py
+++ b/preferences/views.py
@@ -11,8 +11,20 @@ from .forms import CotisationForm, PaymentMethodForm, GeneralPreferencesForm
@active_required
@login_required
-@permission_required('preferences.add_generalpreferences')
+@permission_required('preferences.change_generalpreferences')
def generalPreferences(request):
+ """
+ Display form to edit the general preferences
+
+ **Context**
+
+ ``form``
+ The GeneralPreferences form instance
+
+ **Template**
+
+ :template:`preferences/general_preferences.html`
+ """
gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
form = GeneralPreferencesForm(request.POST or None, instance=gp)
if(form.is_valid()):
@@ -25,6 +37,18 @@ def generalPreferences(request):
@login_required
@permission_required('preferences.view_cotisation')
def cotisationsIndex(request):
+ """
+ Lists the cotisations
+
+ **Context**
+
+ ``cotisations``
+ List of cotisations
+
+ **Template**
+
+ :template:`preferences/cotisations_index.html`
+ """
cotisations = Cotisation.objects.all()
return render(request, "preferences/cotisations_index.html", {"cotisations": cotisations})
@@ -32,6 +56,24 @@ def cotisationsIndex(request):
@login_required
@permission_required('preferences.add_cotisation')
def addCotisation(request):
+ """
+ Form to add a cotisation
+
+ **Context**
+
+ ``form``
+ The CotisationForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the form button
+
+ **Template**
+
+ :template:`form.html`
+ """
form = CotisationForm(request.POST or None)
if(form.is_valid()):
cotisation = form.save()
@@ -43,6 +85,27 @@ def addCotisation(request):
@login_required
@permission_required('preferences.change_cotisation')
def editCotisation(request, pk):
+ """
+ Form to edit a cotisation
+
+ ``pk``
+ The primary key of the cotisation
+
+ **Context**
+
+ ``form``
+ The CotisationForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the form button
+
+ **Template**
+
+ :template:`form.html`
+ """
cotisation = get_object_or_404(Cotisation, pk=pk)
form = CotisationForm(request.POST or None, instance=cotisation)
if(form.is_valid()):
@@ -55,6 +118,12 @@ def editCotisation(request, pk):
@login_required
@permission_required('preferences.delete_cotisation')
def deleteCotisation(request,pk):
+ """
+ Delete a cotisation
+
+ ``pk``
+ The primary key of the cotisation to delete
+ """
cotisation = get_object_or_404(Cotisation, pk=pk)
message = "La cotisation (" + str(cotisation.duration) + " jours, " + str(cotisation.amount) + "€) a bien été supprimée"
cotisation.delete()
@@ -68,6 +137,18 @@ def deleteCotisation(request,pk):
@login_required
@permission_required('preferences.view_paymentmethod')
def paymentMethodsIndex(request):
+ """
+ Lists the paymentMethods
+
+ **Context**
+
+ ``paymentMethods``
+ List of paymentMethods
+
+ **Template**
+
+ :template:`preferences/payment_methods_index.html`
+ """
paymentMethods = PaymentMethod.objects.all()
return render(request, "preferences/payment_methods_index.html", {"paymentMethods": paymentMethods})
@@ -75,6 +156,24 @@ def paymentMethodsIndex(request):
@login_required
@permission_required('preferences.add_paymentmethod')
def addPaymentMethod(request):
+ """
+ Form to add a paymentMethod
+
+ **Context**
+
+ ``form``
+ The CotisationForm form paymentMethod
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the form button
+
+ **Template**
+
+ :template:`form.html`
+ """
form = PaymentMethodForm(request.POST or None)
if(form.is_valid()):
paymentMethod = form.save()
@@ -86,6 +185,27 @@ def addPaymentMethod(request):
@login_required
@permission_required('preferences.change_paymentmethod')
def editPaymentMethod(request, pk):
+ """
+ Form to edit a paymentMethod
+
+ ``pk``
+ The primary key of the paymentMethod
+
+ **Context**
+
+ ``form``
+ The PaymentMethodForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the form button
+
+ **Template**
+
+ :template:`form.html`
+ """
paymentMethod = get_object_or_404(PaymentMethod, pk=pk)
form = PaymentMethodForm(request.POST or None, instance=paymentMethod)
if(form.is_valid()):
@@ -98,8 +218,14 @@ def editPaymentMethod(request, pk):
@login_required
@permission_required('preferences.delete_paymentmethod')
def deletePaymentMethod(request,pk):
+ """
+ Delete a paymentMethod
+
+ ``pk``
+ The primary key of the paymentMethod to delete
+ """
paymentMethod = get_object_or_404(PaymentMethod, pk=pk)
message = "Le moyen de paiement " + paymentMethod.name + " a bien été supprimé"
paymentMethod.delete()
messages.success(request, message)
- return redirect(reverse('preferences:paymentMethodsIndex'))
\ No newline at end of file
+ return redirect(reverse('preferences:paymentMethodsIndex'))
diff --git a/templates/nav.html b/templates/nav.html
index 42f4af2..7244264 100644
--- a/templates/nav.html
+++ b/templates/nav.html
@@ -14,9 +14,6 @@
Classement
-
- Classement sur l'année
-
Admin
diff --git a/users/forms.py b/users/forms.py
index a8f0fd7..4fea80f 100644
--- a/users/forms.py
+++ b/users/forms.py
@@ -4,10 +4,16 @@ from dal import autocomplete
from .models import School, CotisationHistory, WhiteListHistory
class LoginForm(forms.Form):
+ """
+ Form to log in
+ """
username = forms.CharField(max_length=255, label="Nom d'utitisateur")
password = forms.CharField(max_length=255, widget=forms.PasswordInput, label="Mot de passe")
class CreateUserForm(forms.ModelForm):
+ """
+ Form to create a new user
+ """
class Meta:
model = User
fields = ("username", "last_name", "first_name", "email")
@@ -15,35 +21,59 @@ class CreateUserForm(forms.ModelForm):
school = forms.ModelChoiceField(queryset=School.objects.all(), label="École")
class CreateGroupForm(forms.ModelForm):
+ """
+ Form to create a new group
+ """
class Meta:
model = Group
fields = ("name", )
class EditGroupForm(forms.ModelForm):
+ """
+ Form to edit a group
+ """
class Meta:
model = Group
fields = "__all__"
class SelectUserForm(forms.Form):
+ """
+ Form to select a user from all users
+ """
user = forms.ModelChoiceField(queryset=User.objects.all(), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:all-users-autocomplete', attrs={'data-minimum-input-length':2}))
class SelectNonSuperUserForm(forms.Form):
+ """
+ Form to select a user from all non-superuser users
+ """
user = forms.ModelChoiceField(queryset=User.objects.filter(is_active=True), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:non-super-users-autocomplete', attrs={'data-minimum-input-length':2}))
class SelectNonAdminUserForm(forms.Form):
+ """
+ Form to select a user from all non-staff users
+ """
user = forms.ModelChoiceField(queryset=User.objects.filter(is_active=True), required=True, label="Utilisateur", widget=autocomplete.ModelSelect2(url='users:non-admin-users-autocomplete', attrs={'data-minimum-input-length':2}))
class GroupsEditForm(forms.ModelForm):
+ """
+ Form to edit a user's list of groups
+ """
class Meta:
model = User
fields = ("groups", )
class EditPasswordForm(forms.Form):
+ """
+ Form to change the password of a user
+ """
password = forms.CharField(max_length=255, widget=forms.PasswordInput, label="Mot de passe actuel")
password1 = forms.CharField(max_length=255, widget=forms.PasswordInput, label="Nouveau mot de passe")
password2 = forms.CharField(max_length=255, widget=forms.PasswordInput, label="Nouveau mot de passe (répétez)")
def clean_password2(self):
+ """
+ Verify if the two new passwords are identical
+ """
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
@@ -51,16 +81,25 @@ class EditPasswordForm(forms.Form):
return password2
class addCotisationHistoryForm(forms.ModelForm):
+ """
+ Form to add a cotisation to user
+ """
class Meta:
model = CotisationHistory
fields = ("cotisation", "paymentMethod")
class addWhiteListHistoryForm(forms.ModelForm):
+ """
+ Form to add a whitelist to user
+ """
class Meta:
model = WhiteListHistory
fields = ("duration", )
class SchoolForm(forms.ModelForm):
+ """
+ Form to add and edit a school
+ """
class Meta:
model = School
fields = "__all__"
\ No newline at end of file
diff --git a/users/migrations/0005_auto_20181202_1628.py b/users/migrations/0005_auto_20181202_1628.py
new file mode 100644
index 0000000..99a1031
--- /dev/null
+++ b/users/migrations/0005_auto_20181202_1628.py
@@ -0,0 +1,45 @@
+# Generated by Django 2.1 on 2018-12-02 15:28
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('users', '0004_historicalcotisationhistory_historicalprofile_historicalschool_historicalwhitelisthistory'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='cotisationhistory',
+ options={'permissions': (('validate_cotisationhistory', 'Peut (in)valider les cotisations'),), 'verbose_name': 'Historique cotisation'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalcotisationhistory',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Historique cotisation'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalprofile',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Profil'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalschool',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical École'},
+ ),
+ migrations.AlterModelOptions(
+ name='historicalwhitelisthistory',
+ options={'get_latest_by': 'history_date', 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical Historique accès gracieux'},
+ ),
+ migrations.AlterModelOptions(
+ name='profile',
+ options={'verbose_name': 'Profil'},
+ ),
+ migrations.AlterModelOptions(
+ name='school',
+ options={'verbose_name': 'École'},
+ ),
+ migrations.AlterModelOptions(
+ name='whitelisthistory',
+ options={'verbose_name': 'Historique accès gracieux'},
+ ),
+ ]
diff --git a/users/models.py b/users/models.py
index 7799e07..72c97aa 100644
--- a/users/models.py
+++ b/users/models.py
@@ -8,6 +8,12 @@ from preferences.models import PaymentMethod, Cotisation
from gestion.models import ConsumptionHistory
class School(models.Model):
+ """
+ Stores school
+ """
+ class Meta:
+ verbose_name = "École"
+
name = models.CharField(max_length=255, verbose_name="Nom")
history = HistoricalRecords()
@@ -15,9 +21,13 @@ class School(models.Model):
return self.name
class CotisationHistory(models.Model):
+ """
+ Stores cotisations history, related to :model:`preferences.Cotisation`
+ """
class Meta:
+ verbose_name = "Historique cotisation"
permissions = (
- ("validate_consumptionhistory", "Peut (in)valider les cotisations"),
+ ("validate_cotisationhistory", "Peut (in)valider les cotisations"),
)
WAITING = 0
@@ -40,6 +50,12 @@ class CotisationHistory(models.Model):
history = HistoricalRecords()
class WhiteListHistory(models.Model):
+ """
+ Stores whitelist history
+ """
+ class Meta:
+ verbose_name = "Historique accès gracieux"
+
user = models.ForeignKey(User, on_delete=models.PROTECT)
paymentDate = models.DateTimeField(auto_now_add=True)
endDate = models.DateTimeField()
@@ -48,6 +64,12 @@ class WhiteListHistory(models.Model):
history = HistoricalRecords()
class Profile(models.Model):
+ """
+ Stores user profile
+ """
+ class Meta:
+ verbose_name = "Profil"
+
user = models.OneToOneField(User, on_delete=models.CASCADE)
credit = models.DecimalField(max_digits=5, decimal_places=2, default=0)
debit = models.DecimalField(max_digits=5, decimal_places=2, default=0)
@@ -57,6 +79,9 @@ class Profile(models.Model):
@property
def is_adherent(self):
+ """
+ Test if a user is adherent
+ """
if(self.cotisationEnd and self.cotisationEnd > timezone.now()):
return True
else:
@@ -64,17 +89,29 @@ class Profile(models.Model):
@property
def balance(self):
+ """
+ Computes user balance
+ """
return self.credit - self.debit
def positiveBalance(self):
+ """
+ Test if the user balance is positive or null
+ """
return self.balance >= 0
@property
def rank(self):
+ """
+ Computes the rank (by debit) of the user
+ """
return Profile.objects.filter(debit__gte=self.debit).count()
@property
def alcohol(self):
+ """
+ Computes ingerated alcohol
+ """
consumptions = ConsumptionHistory.objects.filter(customer=self.user).select_related('product')
alcohol = 0
for consumption in consumptions:
@@ -87,18 +124,27 @@ class Profile(models.Model):
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
+ """
+ Create profile when user is created
+ """
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
+ """
+ Save profile when user is saved
+ """
instance.profile.save()
def str_user(self):
- if(self.profile.is_adherent):
+ """
+ Rewrite str method for user
+ """
+ if self.profile.is_adherent:
fin = "Adhérent"
else:
fin = "Non adhérent"
return self.username + " (" + self.first_name + " " + self.last_name + ", " + str(self.profile.balance) + "€, " + fin + ")"
-User.add_to_class("__str__", str_user)
\ No newline at end of file
+User.add_to_class("__str__", str_user)
diff --git a/users/views.py b/users/views.py
index 08a85f6..fe9e6cf 100644
--- a/users/views.py
+++ b/users/views.py
@@ -623,6 +623,18 @@ def removeUser(request, groupPk, userPk):
@login_required
@admin_required
def adminsIndex(request):
+ """
+ Lists the staff
+
+ **Context**
+
+ ``admins``
+ List of staff
+
+ **Template**
+
+ :template:`users/admins_index.html`
+ """
admins = User.objects.filter(is_staff=True)
return render(request, "users/admins_index.html", {"admins": admins})
@@ -630,6 +642,24 @@ def adminsIndex(request):
@login_required
@admin_required
def addAdmin(request):
+ """
+ Form to add a member to staff
+
+ **Context**
+
+ ``form``
+ The SelectNonAdminUserForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the button
+
+ **Template**
+
+ :template:`form.html`
+ """
form = SelectNonAdminUserForm(request.POST or None)
if(form.is_valid()):
user = form.cleaned_data['user']
@@ -637,12 +667,18 @@ def addAdmin(request):
user.save()
messages.success(request, "L'utilisateur " + user.username + " a bien été rajouté aux admins")
return redirect(reverse('users:adminsIndex'))
- return render(request, "form.html", {"form_entete": "Gestion des admins", "form": form, "form_title": "Ajout d'un admin", "form_button":"Ajouter l'utilisateur aux admins"})
+ return render(request, "form.html", {"form": form, "form_title": "Ajout d'un admin", "form_button":"Ajouter l'utilisateur aux admins"})
@active_required
@login_required
@admin_required
def removeAdmin(request, pk):
+ """
+ Remove an user form staff
+
+ ``pk``
+ The primary key of the user
+ """
user = get_object_or_404(User, pk=pk)
if user.is_staff:
if user.is_superuser:
@@ -664,6 +700,18 @@ def removeAdmin(request, pk):
@login_required
@superuser_required
def superusersIndex(request):
+ """
+ Lists the superusers
+
+ **Context**
+
+ ``superusers``
+ List of superusers
+
+ **Template**
+
+ :template:`users/superusers_index.html`
+ """
superusers = User.objects.filter(is_superuser=True)
return render(request, "users/superusers_index.html", {"superusers": superusers})
@@ -671,8 +719,26 @@ def superusersIndex(request):
@login_required
@superuser_required
def addSuperuser(request):
+ """
+ Displays a form to add a superuser
+
+ **Context**
+
+ ``form``
+ The SelectNonSuperUserForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the button
+
+ **Template**
+
+ :template:`form.html`
+ """
form = SelectNonSuperUserForm(request.POST or None)
- if(form.is_valid()):
+ if form.is_valid():
user = form.cleaned_data['user']
user.is_admin = True
user.is_superuser = True
@@ -685,6 +751,12 @@ def addSuperuser(request):
@login_required
@superuser_required
def removeSuperuser(request, pk):
+ """
+ Removes a user from superusers
+
+ ``pk``
+ The primary key of the user
+ """
user = get_object_or_404(User, pk=pk)
if user.is_superuser:
if User.objects.filter(is_superuser=True).count() > 1:
@@ -703,6 +775,27 @@ def removeSuperuser(request, pk):
@login_required
@permission_required('users.add_cotisationhistory')
def addCotisationHistory(request, pk):
+ """
+ Add a cotisation to the requested user
+
+ ``pk``
+ The primary key of the user
+
+ **Context**
+
+ ``form``
+ The addCotisationHistoryForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the button
+
+ **Template**
+
+ :template:`form.html`
+ """
user = get_object_or_404(User, pk=pk)
form = addCotisationHistoryForm(request.POST or None)
if(form.is_valid()):
@@ -730,8 +823,14 @@ def addCotisationHistory(request, pk):
@active_required
@login_required
-@permission_required('users.validate_consumptionhistory')
+@permission_required('users.validate_cotisationhistory')
def validateCotisationHistory(request, pk):
+ """
+ Validate the requested :model:`users.CotisationHistory`
+
+ ``pk``
+ The primary key of the :model:`users.CotisationHistory`
+ """
cotisationHistory = get_object_or_404(CotisationHistory, pk=pk)
cotisationHistory.valid = CotisationHistory.VALID
cotisationHistory.save()
@@ -740,8 +839,14 @@ def validateCotisationHistory(request, pk):
@active_required
@login_required
-@permission_required('users.validate_consumptionhistory')
+@permission_required('users.validate_cotisationhistory')
def invalidateCotisationHistory(request, pk):
+ """
+ Invalidate the requested :model:`users.CotisationHistory`
+
+ ``pk``
+ The primary key of the :model:`users.CotisationHistory`
+ """
cotisationHistory = get_object_or_404(CotisationHistory, pk=pk)
cotisationHistory.valid = CotisationHistory.INVALID
cotisationHistory.save()
@@ -759,6 +864,27 @@ def invalidateCotisationHistory(request, pk):
@login_required
@permission_required('users.add_whitelisthistory')
def addWhiteListHistory(request, pk):
+ """
+ Add a :model:`users.WhitelistHistory` to the requested user
+
+ ``pk``
+ The primary key of the user
+
+ **Context**
+
+ ``form``
+ The addWhiteListHistoryForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the button
+
+ **Template**
+
+ :template:`form.html`
+ """
user = get_object_or_404(User, pk=pk)
form = addWhiteListHistoryForm(request.POST or None)
if(form.is_valid()):
@@ -782,6 +908,18 @@ def addWhiteListHistory(request, pk):
@login_required
@permission_required('users.view_school')
def schoolsIndex(request):
+ """
+ Lists the :model:`users.School`
+
+ **Context**
+
+ ``schools``
+ List of the :model:`users.School`
+
+ **Template**
+
+ :template:`users/schools_index.html`
+ """
schools = School.objects.all()
return render(request, "users/schools_index.html", {"schools": schools})
@@ -789,8 +927,26 @@ def schoolsIndex(request):
@login_required
@permission_required('users.add_school')
def createSchool(request):
+ """
+ Displays form to create :model:`users.School`
+
+ **Context**
+
+ ``form``
+ The SchoolForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the button
+
+ **Template**
+
+ :template:`form.html`
+ """
form = SchoolForm(request.POST or None)
- if(form.is_valid()):
+ if form.is_valid():
form.save()
messages.success(request, "L'école a bien été créée")
return redirect(reverse('users:schoolsIndex'))
@@ -800,6 +956,27 @@ def createSchool(request):
@login_required
@permission_required('users.change_school')
def editSchool(request, pk):
+ """
+ Displays form to create :model:`users.School`
+
+ ``pk``
+ The primary key of :model:`users.School`
+
+ **Context**
+
+ ``form``
+ The SchoolForm form instance
+
+ ``form_title``
+ The title of the form
+
+ ``form_button``
+ The text of the button
+
+ **Template**
+
+ :template:`form.html`
+ """
school = get_object_or_404(School, pk=pk)
form = SchoolForm(request.POST or None, instance=school)
if(form.is_valid()):
@@ -812,6 +989,12 @@ def editSchool(request, pk):
@login_required
@permission_required('users.delete_school')
def deleteSchool(request, pk):
+ """
+ Delete a :model:`users.School`
+
+ ``pk``
+ The primary key of the school to delete
+ """
school = get_object_or_404(School, pk=pk)
message = "L'école " + str(school) + " a bien été supprimée"
school.delete()
@@ -821,6 +1004,9 @@ def deleteSchool(request, pk):
########## Autocomplete searchs ##########
class AllUsersAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autcomplete for all users
+ """
def get_queryset(self):
qs = User.objects.all()
if self.q:
@@ -828,6 +1014,9 @@ class AllUsersAutocomplete(autocomplete.Select2QuerySetView):
return qs
class ActiveUsersAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete for active users
+ """
def get_queryset(self):
qs = User.objects.filter(is_active=True)
if self.q:
@@ -835,11 +1024,17 @@ class ActiveUsersAutocomplete(autocomplete.Select2QuerySetView):
return qs
class AdherentAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete for adherents
+ """
def get_queryset(self):
qs = User.objects.all()
return qs
class NonSuperUserAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete for non-superuser users
+ """
def get_queryset(self):
qs = User.objects.filter(is_superuser=False)
if self.q:
@@ -847,6 +1042,9 @@ class NonSuperUserAutocomplete(autocomplete.Select2QuerySetView):
return qs
class NonAdminUserAutocomplete(autocomplete.Select2QuerySetView):
+ """
+ Autocomplete for non-admin users
+ """
def get_queryset(self):
qs = User.objects.filter(is_staff=False)
if self.q: