Browse Source

Merge pull request #14 from nanoy42/release-3.6.3

Release 3.6.3
pull/17/head v3.6.3
Yoann Pietri 6 years ago
committed by GitHub
parent
commit
cb449ee414
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 5
      CHANGELOG.md
  3. 15
      coopeV3/management/commands/gencontributors.py
  4. 4
      coopeV3/urls.py
  5. 69
      coopeV3/views.py
  6. 4
      gestion/admin.py
  7. 53
      gestion/migrations/0012_auto_20190827_2119.py
  8. 10
      gestion/models.py
  9. 3
      gestion/templates/gestion/product_profile.html
  10. 6
      gestion/templates/gestion/products_list.html
  11. 41
      gestion/templates/gestion/stocks.html
  12. 3
      gestion/urls.py
  13. 92
      gestion/views.py
  14. 2
      preferences/views.py
  15. 16
      staticfiles/stocks.js
  16. 6
      templates/about.html
  17. 2
      templates/footer.html
  18. 9
      templates/nav.html
  19. 4
      templates/stats.html

1
.gitignore

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

5
CHANGELOG.md

@ -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

15
coopeV3/management/commands/gencontributors.py

@ -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)

4
coopeV3/urls.py

@ -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)

69
coopeV3/views.py

@ -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,
})

4
gestion/admin.py

@ -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')

53
gestion/migrations/0012_auto_20190827_2119.py

@ -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',
),
]

10
gestion/models.py

@ -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.
"""
stockBar = models.IntegerField(default=0, verbose_name="Stock en bar")
""" """
Number of product at the bar. Number of product
""" """
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) + "°)"

3
gestion/templates/gestion/product_profile.html

@ -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>

6
gestion/templates/gestion/products_list.html

@ -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>

41
gestion/templates/gestion/stocks.html

@ -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 %}

3
gestion/urls.py

@ -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"),
] ]

92
gestion/views.py

@ -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):

2
preferences/views.py

@ -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

@ -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);
});
}
});
});

6
templates/about.html

@ -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 %}

2
templates/footer.html

@ -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>

9
templates/nav.html

@ -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>

4
gestion/templates/gestion/stats.html → templates/stats.html

@ -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>
Loading…
Cancel
Save