3
0
Fork 0
mirror of https://github.com/nanoy42/coope synced 2024-10-05 19:12:09 +00:00

Merge pull request #14 from nanoy42/release-3.6.3

Release 3.6.3
This commit is contained in:
Yoann Pietri 2019-08-28 12:39:03 +02:00 committed by GitHub
commit cb449ee414
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 260 additions and 85 deletions

1
.gitignore vendored
View file

@ -45,3 +45,4 @@ static/
Pipfile Pipfile
mediafiles mediafiles
Pipfile.lock Pipfile.lock
contributors.txt

View file

@ -1,3 +1,8 @@
## v3.6.3
* Refonte totale du système de stocks
* Fix price profile
* Rajoute un nombre de citations sur la page de statistiques
* Fix les contributeurs sur la page about et gencontributors en commande
## v3.6.2 ## v3.6.2
* Fix sur les prix des cotisations. * Fix sur les prix des cotisations.
* Page À propose * Page À propose

View file

@ -0,0 +1,15 @@
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
import subprocess
class Command(BaseCommand):
help = 'Generate the git contributors file'
def handle(self, *args, **options):
try:
subprocess.call("rm " + settings.BASE_DIR + "/contributors.txt", shell=True)
except:
pass
subprocess.call("git -C " + settings.BASE_DIR + " shortlog -n $@ | grep \"):\" | sed 's|:||' >> " + settings.BASE_DIR + "/contributors.txt", shell=True)
subprocess.call("cat " + settings.BASE_DIR + "/contributors.txt", shell=True)

View file

@ -25,11 +25,13 @@ urlpatterns = [
path('home', views.homepage, name="homepage"), path('home', views.homepage, name="homepage"),
path('about', views.about, name="about"), path('about', views.about, name="about"),
path('coope-runner', views.coope_runner, name="coope-runner"), path('coope-runner', views.coope_runner, name="coope-runner"),
path('stats', views.stats, name="stats"),
path('admin/doc/', include('django.contrib.admindocs.urls')), path('admin/doc/', include('django.contrib.admindocs.urls')),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('users/', include('users.urls')), path('users/', include('users.urls')),
path('gestion/', include('gestion.urls')), path('gestion/', include('gestion.urls')),
path('preferences/', include('preferences.urls')), path('preferences/', include('preferences.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -3,9 +3,15 @@ import os
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.urls import reverse from django.urls import reverse
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User, Group
from preferences.models import GeneralPreferences from preferences.models import GeneralPreferences, PaymentMethod, Cotisation
from gestion.models import Keg from gestion.models import Keg, ConsumptionHistory, Category, Product, Menu
from users.models import School
from .acl import active_required, admin_required
def home(request): def home(request):
""" """
@ -38,16 +44,59 @@ def about(request):
""" """
A page about the project A page about the project
""" """
os.system("git -C " + settings.BASE_DIR + " shortlog -n $@ | grep \"):\" | sed 's|:||' >> " + settings.BASE_DIR + "/contributors.txt")
contributors = [] contributors = []
with open(settings.BASE_DIR + "/contributors.txt", "r") as f: try:
for line in f: with open(settings.BASE_DIR + "/contributors.txt", "r") as f:
print(line) for line in f:
print(line.split(" ")[0]) contributors.append((line[:line.find('(')], int(line[(line.find('(') + 1):line.find(')')])))
contributors.append((line.split(" ")[0], int(line.split(" ")[1].replace("(", "").replace(")", "").replace("\n", "")))) except:
os.system("rm " + settings.BASE_DIR + "/contributors.txt") pass
license = [] license = []
with open(settings.BASE_DIR + "/LICENSE", "r") as f: with open(settings.BASE_DIR + "/LICENSE", "r") as f:
for line in f: for line in f:
license.append(line) license.append(line)
return render(request, "about.html", {"contributors": contributors, "license": license}) return render(request, "about.html", {"contributors": contributors, "license": license})
@active_required
@login_required
@admin_required
def stats(request):
users = User.objects.all()
adherents = [x for x in users if x.profile.is_adherent]
transactions = ConsumptionHistory.objects.all()
categories = Category.objects.all()
categories_shown = Category.objects.exclude(order=0)
products = Product.objects.all()
active_products = Product.objects.filter(is_active=True)
active_kegs = Keg.objects.filter(is_active=True)
sum_positive_balance = sum([x.profile.balance for x in users if x.profile.balance > 0])
sum_balance = sum([x.profile.balance for x in users])
schools = School.objects.all()
groups = Group.objects.all()
admins = User.objects.filter(is_staff=True)
superusers = User.objects.filter(is_superuser=True)
menus = Menu.objects.all()
payment_methods = PaymentMethod.objects.all()
cotisations = Cotisation.objects.all()
gp,_ = GeneralPreferences.objects.get_or_create(pk=1)
nb_quotes = len(gp.global_message.split("\n"))
return render(request, "stats.html", {
"users": users,
"adherents": adherents,
"transactions": transactions,
"categories": categories,
"categories_shown": categories_shown,
"products": products,
"active_products": active_products,
"active_kegs": active_kegs,
"sum_positive_balance": sum_positive_balance,
"sum_balance": sum_balance,
"schools": schools,
"groups": groups,
"admins": admins,
"superusers": superusers,
"menus": menus,
"payment_methods": payment_methods,
"cotisations": cotisations,
"nb_quotes": nb_quotes,
})

View file

@ -59,8 +59,8 @@ class ProductAdmin(SimpleHistoryAdmin):
""" """
The admin class for :class:`Products <gestion.models.Product>`. The admin class for :class:`Products <gestion.models.Product>`.
""" """
list_display = ('name', 'amount', 'is_active', 'category', 'adherentRequired', 'stockHold', 'stockBar', 'volume', 'deg') list_display = ('name', 'amount', 'is_active', 'category', 'adherentRequired', 'stock', 'volume', 'deg')
ordering = ('name', 'amount', 'stockHold', 'stockBar', 'deg') ordering = ('name', 'amount', 'stock', 'deg')
search_fields = ('name',) search_fields = ('name',)
list_filter = ('is_active', 'adherentRequired', 'category') list_filter = ('is_active', 'adherentRequired', 'category')

View file

@ -0,0 +1,53 @@
# Generated by Django 2.1 on 2019-08-27 19:19
from django.db import migrations, models
def update(apps, schema_editor):
Product = apps.get_model('gestion', 'Product')
for product in Product.objects.all():
product.stock = product.stockBar
product.save()
def reverse(apps, schema_editor):
Product = apps.get_model('gestion', 'Product')
for product in Product.objects.all():
product.stockBar = product.stock
product.save()
class Migration(migrations.Migration):
dependencies = [
('gestion', '0011_auto_20190623_1640'),
]
operations = [
migrations.AddField(
model_name='historicalproduct',
name='stock',
field=models.IntegerField(default=0, verbose_name='Stock'),
),
migrations.AddField(
model_name='product',
name='stock',
field=models.IntegerField(default=0, verbose_name='Stock'),
),
migrations.RunPython(update, reverse),
migrations.RemoveField(
model_name='historicalproduct',
name='stockBar',
),
migrations.RemoveField(
model_name='historicalproduct',
name='stockHold',
),
migrations.RemoveField(
model_name='product',
name='stockBar',
),
migrations.RemoveField(
model_name='product',
name='stockHold',
),
]

View file

@ -54,13 +54,9 @@ class Product(models.Model):
""" """
The price of the product. The price of the product.
""" """
stockHold = models.IntegerField(default=0, verbose_name="Stock en soute") stock = models.IntegerField(default=0, verbose_name="Stock")
""" """
Number of product in the hold. Number of product
"""
stockBar = models.IntegerField(default=0, verbose_name="Stock en bar")
"""
Number of product at the bar.
""" """
category = models.ForeignKey('Category', on_delete=models.PROTECT, verbose_name="Catégorie") category = models.ForeignKey('Category', on_delete=models.PROTECT, verbose_name="Catégorie")
""" """
@ -95,7 +91,7 @@ class Product(models.Model):
def __str__(self): def __str__(self):
if self.draft_category == self.DRAFT_NONE: if self.draft_category == self.DRAFT_NONE:
return self.name + "(" + str(self.amount) + " €)" return self.name + " (" + str(self.amount) + " €)"
else: else:
return self.name + " (" + str(self.amount) + " €, " + str(self.deg) + "°)" return self.name + " (" + str(self.amount) + " €, " + str(self.deg) + "°)"

View file

@ -14,8 +14,7 @@
{% if perms.gestion.change_product %}<a href="{% url 'gestion:switchActivate' product.pk %}" class="button small">{% if product.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editProduct' product.pk %}" class="button small">Modifier</a><br>{% endif %}<br> {% if perms.gestion.change_product %}<a href="{% url 'gestion:switchActivate' product.pk %}" class="button small">{% if product.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editProduct' product.pk %}" class="button small">Modifier</a><br>{% endif %}<br>
<strong>Nom</strong> : {{ product.name }}<br> <strong>Nom</strong> : {{ product.name }}<br>
<strong>Prix de vente</strong> : {{ product.amount }}€<br> <strong>Prix de vente</strong> : {{ product.amount }}€<br>
<strong>Stock en soute</strong> : {{ product.stockHold }}<br> <strong>Stock en soute</strong> : {{ product.stock }}<br>
<strong>Stock au bar</strong> : {{ product.stockBar }}<br>
<strong>Catégorie</strong> : <a href="{% url 'gestion:categoryProfile' product.category.pk %}">{{ product.category }}</a><br> <strong>Catégorie</strong> : <a href="{% url 'gestion:categoryProfile' product.category.pk %}">{{ product.category }}</a><br>
<strong>Actif</strong> : {{ product.is_active | yesno:"Oui, Non"}}<br> <strong>Actif</strong> : {{ product.is_active | yesno:"Oui, Non"}}<br>
<strong>Dégré</strong> : {{ product.deg }}<br> <strong>Dégré</strong> : {{ product.deg }}<br>

View file

@ -19,8 +19,7 @@
<tr> <tr>
<th>Nom</th> <th>Nom</th>
<th>Prix</th> <th>Prix</th>
<th>Stock (soute)</th> <th>Stock</th>
<th>Stock (bar)</th>
<th>Catégorie</th> <th>Catégorie</th>
<th>Actif</th> <th>Actif</th>
<th>Degré</th> <th>Degré</th>
@ -33,8 +32,7 @@
<tr> <tr>
<td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td> <td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td>
<td>{{ product.amount}}</td> <td>{{ product.amount}}</td>
<td>{{ product.stockHold }}</td> <td>{{ product.stock }}</td>
<td>{{ product.stockBar }}</td>
<td>{{ product.category }}</td> <td>{{ product.category }}</td>
<td>{{ product.is_active | yesno:"Oui, Non"}}</td> <td>{{ product.is_active | yesno:"Oui, Non"}}</td>
<td>{{ product.deg }}</td> <td>{{ product.deg }}</td>

View file

@ -0,0 +1,41 @@
{% extends 'base.html' %}
{% load static %}
{% block entete %}Gestion des produits{% endblock %}
{% block navbar%}
<ul>
{% for category in categories %}
<li><a href="#{{category}}">Stocks {{category}}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% block content %}
{% for category in categories %}
<section id="{{category}}" class="main">
<header class="major">
<h2>Stocks {{category}}</h2>
</header>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Nom</th>
<th>Stock</th>
<th>Mettre à jour</th>
</tr>
</thead>
<tbody>
{% for product in category.active_products %}
<tr id="tr-{{product.pk}}">
<td><a href="{% url 'gestion:productProfile' product.pk %}">{{ product.name }}</a></td>
<td id="stock-{{product.pk}}">{{ product.stock }}</td>
<td><button class="update-stock" data-pk="{{product.pk}}" data-stock="{{product.stock}}" ><i class="fa fa-marker"></i></button></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
{% endfor %}
<script src="{% static 'jquery.js' %}"></script>
<script src="{% static 'stocks.js' %}"></script>
{% endblock %}

View file

@ -52,8 +52,9 @@ urlpatterns = [
path('categoryProfile/<int:pk>', views.categoryProfile, name="categoryProfile"), path('categoryProfile/<int:pk>', views.categoryProfile, name="categoryProfile"),
path('categoriesList', views.categoriesList, name="categoriesList"), path('categoriesList', views.categoriesList, name="categoriesList"),
path('categories-autocomplete', views.CategoriesAutocomplete.as_view(), name="categories-autocomplete"), path('categories-autocomplete', views.CategoriesAutocomplete.as_view(), name="categories-autocomplete"),
path('stats', views.stats, name="stats"),
path('divide', views.divide, name="divide"), path('divide', views.divide, name="divide"),
path('gen_invoice', views.gen_invoice, name="gen_invoice"), path('gen_invoice', views.gen_invoice, name="gen_invoice"),
path('compute-price', views.compute_price_view, name="compute-price"), path('compute-price', views.compute_price_view, name="compute-price"),
path('stocks', views.stocks, name="stocks"),
path('updateStock/<int:pk>', views.update_stock, name="updateStock"),
] ]

View file

@ -161,9 +161,11 @@ def order(request):
kegHistory.amountSold += Decimal(quantity * product.amount) kegHistory.amountSold += Decimal(quantity * product.amount)
kegHistory.save() kegHistory.save()
else: else:
if(product.stockHold > 0): if(product.stock > quantity):
product.stockHold -= 1 product.stock -= quantity
product.save() product.save()
else:
raise Exception("Le stock du produit n'autorise pas l'opération")
consumption, _ = Consumption.objects.get_or_create(customer=user, product=product) consumption, _ = Consumption.objects.get_or_create(customer=user, product=product)
consumption.quantity += quantity consumption.quantity += quantity
consumption.save() consumption.save()
@ -195,9 +197,11 @@ def order(request):
consumption, _ = Consumption.objects.get_or_create(customer=user, product=article) consumption, _ = Consumption.objects.get_or_create(customer=user, product=article)
consumption.quantity += quantity consumption.quantity += quantity
consumption.save() consumption.save()
if(article.stockHold > 0): if(article.stock > quantity):
article.stockHold -= 1 article.stock -= quantity
article.save() article.save()
else:
raise Exception("Le stock du produit " + article.name + "n'autorise pas l'opération")
user.profile.alcohol += Decimal(quantity * float(product.deg) * product.volume * 0.79 /10 /1000) user.profile.alcohol += Decimal(quantity * float(product.deg) * product.volume * 0.79 /10 /1000)
user.save() user.save()
return HttpResponse("La commande a bien été effectuée") return HttpResponse("La commande a bien été effectuée")
@ -282,6 +286,7 @@ def cancel_consumption(request, pk):
""" """
consumption = get_object_or_404(ConsumptionHistory, pk=pk) consumption = get_object_or_404(ConsumptionHistory, pk=pk)
user = consumption.customer user = consumption.customer
product = consumption.product
if consumption.paymentMethod.affect_balance: if consumption.paymentMethod.affect_balance:
user.profile.debit -= consumption.amount user.profile.debit -= consumption.amount
else: else:
@ -291,6 +296,8 @@ def cancel_consumption(request, pk):
consumptionT = Consumption.objects.get(customer=user, product=consumption.product) consumptionT = Consumption.objects.get(customer=user, product=consumption.product)
consumptionT.quantity -= consumption.quantity consumptionT.quantity -= consumption.quantity
consumptionT.save() consumptionT.save()
product.stock += consumption.quantity
product.save()
consumption.delete() consumption.delete()
messages.success(request, "La consommation a bien été annulée") messages.success(request, "La consommation a bien été annulée")
return redirect(reverse('users:profile', kwargs={'pk': user.pk})) return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
@ -311,7 +318,9 @@ def cancel_menu(request, pk):
user.profile.debit -= menu_history.amount user.profile.debit -= menu_history.amount
else: else:
user.profile.direct_debit -= menu_history.amount user.profile.direct_debit -= menu_history.amount
for product in manu_history.menu.articles: for product in menu_history.menu.articles:
product.stock += menu_history.quantity
product.save()
consumptionT = Consumption.objects.get(customer=user, product=product) consumptionT = Consumption.objects.get(customer=user, product=product)
consumptionT -= menu_history.quantity consumptionT -= menu_history.quantity
consumptionT.save() consumptionT.save()
@ -322,6 +331,7 @@ def cancel_menu(request, pk):
return redirect(reverse('users:profile', kwargs={'pk': user.pk})) return redirect(reverse('users:profile', kwargs={'pk': user.pk}))
########## Products ########## ########## Products ##########
@active_required @active_required
@login_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') @acl_or('gestion.add_product', 'gestion.view_product', 'gestion.add_keg', 'gestion.view_keg', 'gestion.change_keg', 'gestion.view_menu', 'gestion.add_menu')
@ -451,6 +461,26 @@ class ActiveProductsAutocomplete(autocomplete.Select2QuerySetView):
qs = qs.filter(name__icontains=self.q) qs = qs.filter(name__icontains=self.q)
return qs return qs
@active_required
@login_required
@permission_required('gestion.change_product')
def update_stock(request, pk):
product = get_object_or_404(Product, pk=pk)
if("stock" in request.GET):
product.stock = request.GET.get("stock")
product.save()
return HttpResponse("Le stock a bien été mis à jour")
@active_required
@login_required
@permission_required('gestion.change_product')
def stocks(request):
"""
View to update stocks of active products
"""
categories = Category.objects.exclude(order=0).order_by("order")
return render(request, "gestion/stocks.html", {"categories": categories})
########## Kegs ########## ########## Kegs ##########
@active_required @active_required
@ -471,8 +501,7 @@ def addKeg(request):
pinte = Product( pinte = Product(
name = "Pinte " + name, name = "Pinte " + name,
amount = pinte_price, amount = pinte_price,
stockHold = 0, stock = 0,
stockBar = 0,
category = form.cleaned_data["category"], category = form.cleaned_data["category"],
needQuantityButton = False, needQuantityButton = False,
is_active = True, is_active = True,
@ -487,8 +516,7 @@ def addKeg(request):
demi = Product( demi = Product(
name = "Demi " + name, name = "Demi " + name,
amount = ceil(5*pinte_price)/10, amount = ceil(5*pinte_price)/10,
stockHold = 0, stock = 0,
stockBar = 0,
category = form.cleaned_data["category"], category = form.cleaned_data["category"],
needQuantityButton = False, needQuantityButton = False,
is_active = True, is_active = True,
@ -504,8 +532,7 @@ def addKeg(request):
galopin = Product( galopin = Product(
name = "Galopin " + name, name = "Galopin " + name,
amount = ceil(2.5 * pinte_price)/10, amount = ceil(2.5 * pinte_price)/10,
stockHold = 0, stock = 0,
stockBar = 0,
category = form.cleaned_data["category"], category = form.cleaned_data["category"],
needQuantityButton = False, needQuantityButton = False,
is_active = True, is_active = True,
@ -1013,7 +1040,9 @@ def divide(request):
"divide_histories": divide_histories, "divide_histories": divide_histories,
} }
) )
########## categories ########## ########## categories ##########
@active_required @active_required
@login_required @login_required
@permission_required('gestion.add_category') @permission_required('gestion.add_category')
@ -1091,47 +1120,6 @@ class CategoriesAutocomplete(autocomplete.Select2QuerySetView):
qs = qs.filter(name__icontains=self.q) qs = qs.filter(name__icontains=self.q)
return qs return qs
@active_required
@login_required
@admin_required
def stats(request):
users = User.objects.all()
adherents = [x for x in users if x.profile.is_adherent]
transactions = ConsumptionHistory.objects.all()
categories = Category.objects.all()
categories_shown = Category.objects.exclude(order=0)
products = Product.objects.all()
active_products = Product.objects.filter(is_active=True)
active_kegs = Keg.objects.filter(is_active=True)
sum_positive_balance = sum([x.profile.balance for x in users if x.profile.balance > 0])
sum_balance = sum([x.profile.balance for x in users])
schools = School.objects.all()
groups = Group.objects.all()
admins = User.objects.filter(is_staff=True)
superusers = User.objects.filter(is_superuser=True)
menus = Menu.objects.all()
payment_methods = PaymentMethod.objects.all()
cotisations = Cotisation.objects.all()
return render(request, "gestion/stats.html", {
"users": users,
"adherents": adherents,
"transactions": transactions,
"categories": categories,
"categories_shown": categories_shown,
"products": products,
"active_products": active_products,
"active_kegs": active_kegs,
"sum_positive_balance": sum_positive_balance,
"sum_balance": sum_balance,
"schools": schools,
"groups": groups,
"admins": admins,
"superusers": superusers,
"menus": menus,
"payment_methods": payment_methods,
"cotisations": cotisations,
})
########## Compute price ########## ########## Compute price ##########
def compute_price_view(request): def compute_price_view(request):

View file

@ -242,6 +242,6 @@ def delete_price_profile(request,pk):
""" """
price_profile = get_object_or_404(PriceProfile, pk=pk) price_profile = get_object_or_404(PriceProfile, pk=pk)
message = "Le profil de prix " + price_profile.name + " a bien été supprimé" message = "Le profil de prix " + price_profile.name + " a bien été supprimé"
price_pofile.delete() price_profile.delete()
messages.success(request, message) messages.success(request, message)
return redirect(reverse('preferences:priceProfilesIndex')) return redirect(reverse('preferences:priceProfilesIndex'))

16
staticfiles/stocks.js Normal file
View file

@ -0,0 +1,16 @@
$(document).ready(function(){
$(".update-stock").click(function(){
var pk = $(this).attr('data-pk');
var current_value = $(this).attr('data-stock');
var ok = false;
while(!ok){
var new_stock = prompt("Nouveau stock ? (entier attendu)", current_value);
ok = new_stock == null || !(isNaN(parseInt(new_stock)));
}
if(new_stock != null){
$.get("/gestion/updateStock/" + pk, {"stock": new_stock}, function(data){
$("#stock-"+pk).html(new_stock);
});
}
});
});

View file

@ -28,8 +28,6 @@
{% endfor %} {% endfor %}
(<a href="https://github.com/nanoy42/coope/blob/master/LICENSE" target="_blank">https://github.com/nanoy42/coope/blob/master/LICENSE</a>). (<a href="https://github.com/nanoy42/coope/blob/master/LICENSE" target="_blank">https://github.com/nanoy42/coope/blob/master/LICENSE</a>).
<br><br> <br><br>
Version 3.6.2.
</section> </section>
</section> </section>
<section id="third" class="main"> <section id="third" class="main">
@ -37,12 +35,16 @@
<h2>Contributeurs</h2> <h2>Contributeurs</h2>
</header> </header>
<section> <section>
{% if contributors %}
Les contributeurs, triés par ordre décroissant de nombre de commits, sont: Les contributeurs, triés par ordre décroissant de nombre de commits, sont:
<ol> <ol>
{% for contributor in contributors %} {% for contributor in contributors %}
<li>{{contributor.0}} ({{contributor.1}} commits)</li> <li>{{contributor.0}} ({{contributor.1}} commits)</li>
{% endfor %} {% endfor %}
</ol> </ol>
{% else %}
Impossible d'afficher la liste des contributeurs
{% endif %}
</section> </section>
</section> </section>
{% endblock %} {% endblock %}

View file

@ -42,6 +42,6 @@
<li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li> <li><a href="https://www.facebook.com/coopesmetz/" class="icon fa-facebook alt"><span class="label">Facebook</span></a></li>
</ul> </ul>
</section> </section>
<p class="copyright">coope.rez v3.6.2 (release stable) &copy; 2018-2019 Yoann Pietri. <a href="{% url 'about'%}">À propos du projet</a>.</p> <p class="copyright">coope.rez v3.6.3 (release stable) &copy; 2018-2019 Yoann Pietri. <a href="{% url 'about'%}">À propos du projet</a>.</p>

View file

@ -20,8 +20,13 @@
<i class="fa fa-dolly-flatbed"></i> <a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a> <i class="fa fa-dolly-flatbed"></i> <a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a>
</span> </span>
{% endif %} {% endif %}
{% if perms.gestion.change_product %}
<span class="tabulation2">
<br>
<i class="fa fa-boxes"></i> <a href="{% url 'gestion:stocks' %}">Stocks</a>
</span>
{% endif %}
<span class="tabulation2"> <span class="tabulation2">
<br>
<i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a> <i class="fa fa-list-ol"></i> <a href="{% url 'gestion:ranking' %}">Classement</a>
</span> </span>
{% if perms.preferences.change_generalpreferences %} {% if perms.preferences.change_generalpreferences %}
@ -31,7 +36,7 @@
{% endif %} {% endif %}
{% if request.user.is_staff %} {% if request.user.is_staff %}
<span class="tabulation2"> <span class="tabulation2">
<i class="fa fa-chart-bar"></i> <a href="{% url 'gestion:stats' %}">Stats</a> <i class="fa fa-chart-bar"></i> <a href="{% url 'stats' %}">Stats</a>
</span> </span>
<span class="tabulation2"> <span class="tabulation2">
<i class="fa fa-business-time"></i> <a href="{% url 'gestion:gen_releve' %}">Relevé</a> <i class="fa fa-business-time"></i> <a href="{% url 'gestion:gen_releve' %}">Relevé</a>

View file

@ -63,6 +63,10 @@
<td>Nombre de superusers</td> <td>Nombre de superusers</td>
<td>{{superusers.count}}</td> <td>{{superusers.count}}</td>
</tr> </tr>
<tr>
<td>Nombre de citations</td>
<td>{{nb_quotes}}</td>
</tr>
<tr> <tr>
<td>Nombre 8</td> <td>Nombre 8</td>
<td>8</td> <td>8</td>