mirror of
https://github.com/nanoy42/coope
synced 2024-11-22 03:13:12 +00:00
On avance encore un peu
This commit is contained in:
parent
a45d7746f5
commit
a78828375c
13 changed files with 214 additions and 49 deletions
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -1,3 +1,6 @@
|
|||
{
|
||||
"python.pythonPath": "/home/nanoy/.virtualenvs/coopeV3/bin/python"
|
||||
"python.pythonPath": "/home/nanoy/.virtualenvs/coopeV3/bin/python",
|
||||
"python.linting.pylintArgs": [
|
||||
"--load-plugins=pylint_django"
|
||||
],
|
||||
}
|
|
@ -9,13 +9,13 @@ def admin_required(view):
|
|||
"""
|
||||
Test if the user is staff
|
||||
"""
|
||||
return user_passes_test(view, lambda u:u.is_staff)
|
||||
return user_passes_test(lambda u: u.is_staff)(view)
|
||||
|
||||
def superuser_required(view):
|
||||
"""
|
||||
Test if the user is superuser
|
||||
"""
|
||||
return user_passes_test(view, lambda u:u.is_superuser)
|
||||
return user_passes_test(lambda u: u.is_superuser)(view)
|
||||
|
||||
def self_or_has_perm(pkName, perm):
|
||||
"""
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
{% if forloop.counter0|divisibleby:4 %}
|
||||
<tr style="text-align:center">
|
||||
{% endif %}
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="{{product.typeSaisie}}">{{product.nom}}</button></td>
|
||||
<td><button class="product" target="{{product.barcode}}">{{product.name}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -136,7 +136,7 @@
|
|||
{% if forloop.counter0|divisibleby:4 %}
|
||||
<tr style="text-align:center">
|
||||
{% endif %}
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="{{product.typeSaisie}}">{{product.nom}}</button></td>
|
||||
<td><button class="product" target="{{product.barcode}}">{{product.name}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -146,11 +146,11 @@
|
|||
{% endif %}
|
||||
|
||||
<tr style="text-align:center; font-weight:bold;"><td colspan="4">Bouffe</td></tr>
|
||||
{% for product in autreBouffe %}
|
||||
{% for product in food %}
|
||||
{% if forloop.counter0|divisibleby:4 %}
|
||||
<tr style="text-align:center">
|
||||
{% endif %}
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="{{product.typeSaisie}}">{{product.nom}}</button></td>
|
||||
<td><button class="product" target="{{product.barcode}}">{{product.name}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -164,7 +164,7 @@
|
|||
{% if forloop.counter0|divisibleby:4 %}
|
||||
<tr style="text-align:center">
|
||||
{% endif %}
|
||||
<td><button class="boutonsProduit" disabled target="{{product.codeBarre}}" type="MN">{{product.nom}}</button></td>
|
||||
<td><button class="product" target="{{product.barcode}}">{{product.name}}</button></td>
|
||||
{% if forloop.counter|divisibleby:4 %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
|
41
gestion/templates/gestion/menus_list.html
Normal file
41
gestion/templates/gestion/menus_list.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block entete %}<h1>Gestion des produits</h1>{% endblock %}
|
||||
{% block navbar%}
|
||||
<ul>
|
||||
<li><a href="#first">Liste des menus</a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<section id="first" class="main">
|
||||
<header class="major">
|
||||
<h2>Liste des menus</h2>
|
||||
</header>
|
||||
<a class="button" href="{% url 'gestion:addMenu' %}">Créer un menu</a><br><br>
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Prix</th>
|
||||
<th>Code barre</th>
|
||||
<th>Produits</th>
|
||||
<th>Actif</th>
|
||||
<th>Administrer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for menu in menus %}
|
||||
<tr>
|
||||
<td>{{ menu.name }}</td>
|
||||
<td>{{ menu.amount}} €</td>
|
||||
<td>{{ menu.barcode }}</td>
|
||||
<td>{% for art in menu.articles.all %}{{art}},{% endfor %}</td>
|
||||
<td>{{ menu.is_active | yesno:"Oui, Non"}}</td>
|
||||
<td><a href="{% url 'gestion:switchActivateMenu' menu.pk %}" class="button small">{% if menu.is_active %}Désa{% else %}A{% endif %}ctiver</a> <a href="{% url 'gestion:editMenu' menu.pk %}" class="button small">Modifier</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -10,14 +10,14 @@
|
|||
<header class="major">
|
||||
<h2>Général</h2>
|
||||
</header>
|
||||
<a class="button small">(Dés)Activer</a> <a class="button small">Modifier</a> <a href="#" class="button small">Supprimer</a><br>
|
||||
<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>
|
||||
<strong>Nom</strong> : {{ product.name }}<br>
|
||||
<strong>Prix de vente</strong> : {{ product.amount }}€<br>
|
||||
<strong>Stock en soute</strong> : {{ product.stockHold }}<br>
|
||||
<strong>Stock au bar</strong> : {{ product.stockBar }}<br>
|
||||
<strong>Code Barre</strong> : {{ product.barcode }}<br>
|
||||
<strong>Catégorie</strong> : {{ product.category }}<br>
|
||||
<strong>Actif</strong> : {{ product.active }}<br>
|
||||
<strong>Actif</strong> : {{ product.is_active | yesno:"Oui, Non"}}<br>
|
||||
<strong>Dégré</strong> : {{ product.deg }}<br>
|
||||
<strong>Volume</strong> : {{ product.volume }}cl<br>
|
||||
</section>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
<li><a href="#first">Produits</a></li>
|
||||
<li><a href="#second">Futs</a></li>
|
||||
<li><a href="#third">Menus</a></li>
|
||||
<li><a href="#fourth">Stocks</a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
@ -39,18 +38,8 @@
|
|||
Actions possibles :
|
||||
<ul>
|
||||
<li><a href="{% url 'gestion:addMenu' %}">Créer un menu</a></li>
|
||||
<li><a href="">Rechercher un menu</a></li>
|
||||
<li><a href="{% url 'users:adminsIndex' %}">Lister les menus</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="fourth" class="main">
|
||||
<header class="major">
|
||||
<h2>Stocks</h2>
|
||||
</header>
|
||||
Actions possibles :
|
||||
<ul>
|
||||
<li><a href="{% url 'users:addSuperuser' %}">Voir les Stocks</a></li>
|
||||
<li><a href="{% url 'users:superusersIndex' %}">Classement sur un produit</a></li>
|
||||
<li><a href="{% url 'gestion:searchMenu' %}">Rechercher un menu</a></li>
|
||||
<li><a href="{% url 'gestion:menusList' %}">Lister les menus</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -36,10 +36,10 @@
|
|||
<td>{{ product.stockBar }}</td>
|
||||
<td>{{ product.barcode }}</td>
|
||||
<td>{{ product.category }}</td>
|
||||
<td>{{ product.is_active }}</td>
|
||||
<td>{{ product.degree }}</td>
|
||||
<td>{{ product.volume }}</td>
|
||||
<td></td>
|
||||
<td>{{ product.is_active | yesno:"Oui, Non"}}</td>
|
||||
<td>{{ product.deg }}</td>
|
||||
<td>{{ product.volume }} cl</td>
|
||||
<td><a href="{% url 'gestion:productProfile' product.pk %}" class="button small">Profil</a> <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></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -10,6 +10,8 @@ urlpatterns = [
|
|||
path('productsIndex', views.productsIndex, name="productsIndex"),
|
||||
path('productsList', views.productsList, name="productsList"),
|
||||
path('addProduct', views.addProduct, name="addProduct"),
|
||||
path('editProduct/<int:pk>', views.editProduct, name="editProduct"),
|
||||
path('switchActivate/<int:pk>', views.switch_activate, name="switchActivate"),
|
||||
path('addKeg', views.addKeg, name="addKeg"),
|
||||
path('openKeg', views.openKeg, name="openKeg"),
|
||||
path('closeKeg', views.closeKeg, name="closeKeg"),
|
||||
|
@ -19,6 +21,10 @@ urlpatterns = [
|
|||
path('openDirectKeg/<int:pk>', views.openDirectKeg, name="openDirectKeg"),
|
||||
path('closeDirectKeg/<int:pk>', views.closeDirectKeg, name="closeDirectKeg"),
|
||||
path('addMenu', views.addMenu, name="addMenu"),
|
||||
path('searchMenu', views.searchMenu, name="searchMenu"),
|
||||
path('editMenu/<int:pk>', views.edit_menu, name="editMenu"),
|
||||
path('menusList', views.menus_list, name="menusList"),
|
||||
path('swicthActivateMenu/<int:pk>', views.switch_activate_menu, name="switchActivateMenu"),
|
||||
path('getProduct/<str:barcode>', views.getProduct, name="getProduct"),
|
||||
path('order', views.order, name="order"),
|
||||
path('ranking', views.ranking, name="ranking"),
|
||||
|
@ -28,5 +34,5 @@ urlpatterns = [
|
|||
path('products-autocomplete', views.ProductsAutocomplete.as_view(), name="products-autocomplete"),
|
||||
path('kegs-positive-autocomplete', views.KegPositiveAutocomplete.as_view(), name="kegs-positive-autocomplete"),
|
||||
path('kegs-active-autocomplete', views.KegActiveAutocomplete.as_view(), name="kegs-active-autocomplete"),
|
||||
|
||||
path('menus-autcomplete', views.MenusAutocomplete.as_view(), name="menus-autocomplete"),
|
||||
]
|
|
@ -155,9 +155,20 @@ def addProduct(request):
|
|||
if(form.is_valid()):
|
||||
form.save()
|
||||
messages.success(request, "Le produit a bien été ajouté")
|
||||
return redirect(reverse('gestion:productsIndex'))
|
||||
return redirect(reverse('gestion:productsList'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Ajout d'un produit", "form_button": "Ajouter"})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.edit_product')
|
||||
def editProduct(request, pk):
|
||||
product = get_object_or_404(Product, pk=pk)
|
||||
form = ProductForm(request.POST or None, instance=product)
|
||||
if(form.is_valid()):
|
||||
form.save()
|
||||
messages.success(request, "Le produit a bien été modifié")
|
||||
return redirect(reverse('gestion:productsList'))
|
||||
return render(request, "form.html", {"form": form, "form_title": "Modification d'un produit", "form_button": "Modifier"})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_product')
|
||||
def productsList(request):
|
||||
|
@ -184,11 +195,24 @@ def getProduct(request, barcode):
|
|||
data = json.dumps({"pk": product.pk, "barcode" : product.barcode, "name": product.name, "amount" : product.amount})
|
||||
return HttpResponse(data, content_type='application/json')
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.edit_product')
|
||||
def switch_activate(request, pk):
|
||||
"""
|
||||
If the product is active, switch to not active.
|
||||
If the product is not active, switch to active.
|
||||
"""
|
||||
product = get_object_or_404(Product, pk=pk)
|
||||
product.is_active = 1 - product.is_active
|
||||
product.save()
|
||||
messages.success(request, "La disponibilité du produit a bien été changée")
|
||||
return redirect(reverse('gestion:productsList'))
|
||||
|
||||
class ProductsAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
qs = Product.objects.all()
|
||||
if self.q:
|
||||
qs = qs.filter(name__istartswith=self.q)
|
||||
qs = qs.filter(name__istartswith=self.q)
|
||||
return qs
|
||||
|
||||
########## Kegs ##########
|
||||
|
@ -325,9 +349,20 @@ def addMenu(request):
|
|||
if(form.is_valid()):
|
||||
menu = form.save()
|
||||
messages.success(request, "Le menu " + menu.name + " a bien été ajouté")
|
||||
return redirect(reverse('gestion:productsIndex'))
|
||||
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})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.edit_menu')
|
||||
def edit_menu(request, pk):
|
||||
menu = get_object_or_404(Menu, pk=pk)
|
||||
form = MenuForm(request.POST or None, instance=menu)
|
||||
extra_css = "#id_articles{height:200px;}"
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, "Le menu a bien été modifié")
|
||||
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})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_menu')
|
||||
|
@ -352,10 +387,29 @@ def searchMenu(request):
|
|||
"""
|
||||
form = SearchMenuForm(request.POST or None)
|
||||
if(form.is_valid()):
|
||||
menu = form.menu
|
||||
return redirect(reverse('gestion:changeMenu', kwargs={'pk':menu.pk}))
|
||||
menu = form.cleaned_data['menu']
|
||||
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"})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.view_menu')
|
||||
def menus_list(request):
|
||||
menus = Menu.objects.all()
|
||||
return render(request, "gestion/menus_list.html", {"menus": menus})
|
||||
|
||||
@login_required
|
||||
@permission_required('gestion.edit_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.
|
||||
"""
|
||||
menu = get_object_or_404(Menu, pk=pk)
|
||||
menu.is_active = 1 - menu.is_active
|
||||
menu.save()
|
||||
messages.success(request, "La disponibilité du menu a bien été changée")
|
||||
return redirect(reverse('gestion:menusList'))
|
||||
|
||||
class MenusAutocomplete(autocomplete.Select2QuerySetView):
|
||||
def get_queryset(self):
|
||||
qs = Menu.objects.all()
|
||||
|
|
10
staticfiles/chart.min.js
vendored
Normal file
10
staticfiles/chart.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -11,9 +11,6 @@
|
|||
<span class="tabulation2">
|
||||
<a href="{% url 'gestion:productsIndex' %}">Gestion des produits</a>
|
||||
</span>
|
||||
<span class="tabulation2">
|
||||
<a href="{% url 'gestion:annualRanking' %}">Comptabilité</a>
|
||||
</span>
|
||||
<span class="tabulation2">
|
||||
<a href="{% url 'gestion:ranking' %}">Classement</a>
|
||||
</span>
|
||||
|
|
|
@ -81,6 +81,47 @@
|
|||
</div>
|
||||
</div>
|
||||
<section class="row uniform">
|
||||
<canvas id="myChart" width="2000px" height="2000px"></canvas>
|
||||
<script src="{% static 'chart.min.js' %}"></script>
|
||||
<script>
|
||||
var ctx = document.getElementById("myChart").getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: [{% for p in products %}"{{p}}", {% endfor %}],
|
||||
datasets: [{
|
||||
label: '# of Votes',
|
||||
data: [{% for q in quantities %}{{q}}, {% endfor %}],
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
'rgba(54, 162, 235, 0.2)',
|
||||
'rgba(255, 206, 86, 0.2)',
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(153, 102, 255, 0.2)',
|
||||
'rgba(255, 159, 64, 0.2)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255,99,132,1)',
|
||||
'rgba(54, 162, 235, 1)',
|
||||
'rgba(255, 206, 86, 1)',
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(153, 102, 255, 1)',
|
||||
'rgba(255, 159, 64, 1)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</section>
|
||||
</section>
|
||||
<section id="second" class="main">
|
||||
|
@ -102,11 +143,14 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody id="bodyTransaction">
|
||||
{% for consumption in consumptions %}
|
||||
{% for c in lastConsumptions %}
|
||||
<tr>
|
||||
{% for part in consumption %}
|
||||
<th>{{part}}</th>
|
||||
{%endfor%}
|
||||
<td>{{c.product}}</td>
|
||||
<td>{{c.quantity}}</td>
|
||||
<td>{{c.amount}}</td>
|
||||
<td>{{c.paymentMethod}}</td>
|
||||
<td>{{c.date}}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
</tbody>
|
||||
|
@ -119,22 +163,22 @@
|
|||
<h2>{{self | yesno:"Mes derniers,Derniers"}} rechargements</h2>
|
||||
<p>(Affichage des 5 dernières entrées)</p>
|
||||
</header>
|
||||
<section id="rechargements">
|
||||
<section>
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead id="headRechargement">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Montant</th>
|
||||
<th>Type de Rechargement</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="bodyRechargement">
|
||||
<tbody>
|
||||
{% for reload in reloads %}
|
||||
<tr>
|
||||
<th>{{reload.amount}}€</th>
|
||||
<th>{{reload.PaymentMethod}}</th>
|
||||
<th>{{reload.date}}</th>
|
||||
<td>{{reload.amount}}€</td>
|
||||
<td>{{reload.PaymentMethod}}</td>
|
||||
<td>{{reload.date}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -15,7 +15,7 @@ from dal import autocomplete
|
|||
from coopeV3.acl import admin_required, superuser_required, self_or_has_perm, active_required
|
||||
from .models import CotisationHistory, WhiteListHistory, School
|
||||
from .forms import CreateUserForm, LoginForm, CreateGroupForm, EditGroupForm, SelectUserForm, GroupsEditForm, EditPasswordForm, addCotisationHistoryForm, addCotisationHistoryForm, addWhiteListHistoryForm, SelectNonAdminUserForm, SelectNonSuperUserForm, SchoolForm
|
||||
from gestion.models import Reload
|
||||
from gestion.models import Reload, Consumption, ConsumptionHistory
|
||||
|
||||
@active_required
|
||||
def loginView(request):
|
||||
|
@ -112,7 +112,28 @@ def profile(request, pk):
|
|||
cotisations = CotisationHistory.objects.filter(user=user)
|
||||
whitelists = WhiteListHistory.objects.filter(user=user)
|
||||
reloads = Reload.objects.filter(customer=user).order_by('-date')
|
||||
return render(request, "users/profile.html", {"user":user, "self":self, "cotisations":cotisations, "whitelists": whitelists, "reloads": reloads})
|
||||
consumptionsChart = Consumption.objects.filter(customer=user)
|
||||
products = []
|
||||
quantities = []
|
||||
for ch in consumptionsChart:
|
||||
if ch.product in products:
|
||||
i = products.index(ch.product)
|
||||
quantities[i] += ch.quantity
|
||||
else:
|
||||
products.append(ch.product)
|
||||
quantities.append(ch.quantity)
|
||||
lastConsumptions = ConsumptionHistory.objects.filter(customer=user).order_by('-date')[:10]
|
||||
return render(request, "users/profile.html",
|
||||
{
|
||||
"user":user,
|
||||
"self":self,
|
||||
"cotisations":cotisations,
|
||||
"whitelists": whitelists,
|
||||
"reloads": reloads,
|
||||
"products": products,
|
||||
"quantities": quantities,
|
||||
"lastConsumptions": lastConsumptions
|
||||
})
|
||||
|
||||
@active_required
|
||||
@login_required
|
||||
|
|
Loading…
Reference in a new issue